diff --git a/Podfile b/Podfile index 0883eb3459..07b2798645 100644 --- a/Podfile +++ b/Podfile @@ -47,10 +47,6 @@ pod 'SQLCipher', ">= 4.0.1" pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master' # pod 'Mantle', path: '../Mantle' -# Forked for compatibily with the ShareExtension, changes have an open PR, but have not been merged. -pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release' -# pod 'YapDatabase/SQLCipher', path: '../YapDatabase' - # Forked to incorporate our self-built binary artifact. pod 'GRKOpenSSLFramework', git: 'https://github.com/signalapp/GRKOpenSSLFramework', branch: 'mkirk/1.0.2t' #pod 'GRKOpenSSLFramework', path: '../GRKOpenSSLFramework' diff --git a/Podfile.lock b/Podfile.lock index 8119b3a809..da3a02d9f3 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -113,7 +113,6 @@ PODS: - SignalMetadataKit - Starscream - SwiftProtobuf - - YapDatabase/SQLCipher - YYImage/WebP - SignalServiceKit/Tests (0.9.0): - AFNetworking/NSURLSession @@ -134,7 +133,6 @@ PODS: - SignalMetadataKit - Starscream - SwiftProtobuf - - YapDatabase/SQLCipher - YYImage/WebP - SQLCipher (4.3.0): - SQLCipher/standard (= 4.3.0) @@ -144,68 +142,6 @@ PODS: - SSZipArchive (2.1.4) - Starscream (3.0.6) - SwiftProtobuf (1.7.0) - - YapDatabase/SQLCipher (3.1.1): - - YapDatabase/SQLCipher/Core (= 3.1.1) - - YapDatabase/SQLCipher/Extensions (= 3.1.1) - - YapDatabase/SQLCipher/Core (3.1.1): - - CocoaLumberjack - - SQLCipher (>= 3.4.0) - - YapDatabase/SQLCipher/Extensions (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/ActionManager (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/AutoView (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/CloudCore (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/CloudKit (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/ConnectionPool (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/ConnectionProxy (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/CrossProcessNotification (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/FilteredView (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/FullTextSearch (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/Hooks (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/ManualView (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/Relationships (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/RTreeIndex (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/SearchResultsView (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/SecondaryIndex (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/View (= 3.1.1) - - YapDatabase/SQLCipher/Extensions/ActionManager (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/AutoView - - YapDatabase/SQLCipher/Extensions/AutoView (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/View - - YapDatabase/SQLCipher/Extensions/CloudCore (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/CloudKit (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/ConnectionPool (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/ConnectionProxy (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/CrossProcessNotification (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/FilteredView (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/View - - YapDatabase/SQLCipher/Extensions/FullTextSearch (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/Hooks (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/ManualView (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/View - - YapDatabase/SQLCipher/Extensions/Relationships (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/RTreeIndex (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/SearchResultsView (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/AutoView - - YapDatabase/SQLCipher/Extensions/FullTextSearch - - YapDatabase/SQLCipher/Extensions/SecondaryIndex (3.1.1): - - YapDatabase/SQLCipher/Core - - YapDatabase/SQLCipher/Extensions/View (3.1.1): - - YapDatabase/SQLCipher/Core - YYImage (1.0.4): - YYImage/Core (= 1.0.4) - YYImage/Core (1.0.4) @@ -246,7 +182,6 @@ DEPENDENCIES: - SSZipArchive - Starscream (from `https://github.com/signalapp/Starscream.git`, branch `signal-release`) - SwiftProtobuf (= 1.7.0) - - YapDatabase/SQLCipher (from `https://github.com/signalapp/YapDatabase.git`, branch `signal-release`) - YYImage (from `https://github.com/signalapp/YYImage`) - ZKGroup (from `https://github.com/signalapp/signal-zkgroup-swift`) - ZKGroup/Tests (from `https://github.com/signalapp/signal-zkgroup-swift`) @@ -301,9 +236,6 @@ EXTERNAL SOURCES: Starscream: :branch: signal-release :git: https://github.com/signalapp/Starscream.git - YapDatabase: - :branch: signal-release - :git: https://github.com/signalapp/YapDatabase.git YYImage: :git: https://github.com/signalapp/YYImage ZKGroup: @@ -343,9 +275,6 @@ CHECKOUT OPTIONS: Starscream: :commit: b09ea163c3cb305152c65b299cb024610f52e735 :git: https://github.com/signalapp/Starscream.git - YapDatabase: - :commit: e43ab163b2dcb4c817339c819b07dac545f05fea - :git: https://github.com/signalapp/YapDatabase.git YYImage: :commit: d91910e6f313a255febbf69795198e74259bd51c :git: https://github.com/signalapp/YYImage @@ -377,16 +306,15 @@ SPEC CHECKSUMS: SignalCoreKit: 43daa8f15d6125d54705f35628ac35051bb205c6 SignalMetadataKit: eb928ec98376ab5a6ef2108a7fcd3b2d792b8c65 SignalRingRTC: 1769d40e1a155a2d6ddd95c404e7822bedd97076 - SignalServiceKit: b3337d511fc32129c8b8819a9ac2700490ecdd6f + SignalServiceKit: 998e9bce294e9e4eb88b13ccd58f7016bb0c8021 SQLCipher: d305a7bd9af4b64f095c79bdc1a1fa50f2a15116 SSZipArchive: 41455d4b8d2b6ab93990820b50dc697c2554a322 Starscream: 8aaf1a7feb805c816d0e7d3190ef23856f6665b9 SwiftProtobuf: 4fd9645e69b72cbae6ec8da5be0cdd20ca6565dd - YapDatabase: b418a4baa6906e8028748938f9159807fd039af4 YYImage: 6db68da66f20d9f169ceb94dfb9947c3867b9665 ZKGroup: 15a08eed5870a44b9dd14af0824ac95f6eed7380 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 8470f6214af1e5e4c437a903764cb001011d8167 +PODFILE CHECKSUM: 6fcda6d7001d5be6e25668298eb82fe1325dba06 COCOAPODS: 1.9.2 diff --git a/Scripts/sds_codegen/sds_generate.py b/Scripts/sds_codegen/sds_generate.py index 3358d31ffa..f8c7514309 100755 --- a/Scripts/sds_codegen/sds_generate.py +++ b/Scripts/sds_codegen/sds_generate.py @@ -1622,14 +1622,12 @@ public extension %(class_name)s { swift_body += ''' switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return %(class_name)s.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(%(record_name)s.databaseTableName) WHERE \(%(record_identifier)sColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) } } -''' % { "class_name": str(clazz.name), "record_name": record_name, "record_identifier": record_identifier(clazz.name) } +''' % { "record_name": record_name, "record_identifier": record_identifier(clazz.name) } swift_body += ''' // Traverses all records. @@ -1656,14 +1654,6 @@ public extension %(class_name)s { batchSize: UInt, block: @escaping (%s, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - %s.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? %s else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = %s.grdbFetchCursor(transaction: grdbTransaction) @@ -1680,7 +1670,7 @@ public extension %(class_name)s { } } } -''' % ( ( str(clazz.name), ) * 6 ) +''' % ( ( str(clazz.name), ) * 4 ) swift_body += ''' // Traverses all records' unique ids. @@ -1707,10 +1697,6 @@ public extension %(class_name)s { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: %s.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -1721,7 +1707,7 @@ public extension %(class_name)s { block: block) } } -''' % ( str(clazz.name), record_identifier(clazz.name), record_name, ) +''' % ( record_identifier(clazz.name), record_name, ) swift_body += ''' // Does not order the results. @@ -1748,13 +1734,11 @@ public extension %(class_name)s { swift_body += ''' class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: %s.collection()) case .grdbRead(let grdbTransaction): return %s.ows_fetchCount(grdbTransaction.database) } } -''' % ( str(clazz.name), record_name, ) +''' % ( record_name, ) # ---- Remove All ---- @@ -1763,8 +1747,6 @@ public extension %(class_name)s { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: %s.collection()) case .grdbWrite(let grdbTransaction): do { try %s.deleteAll(grdbTransaction.database) @@ -1813,8 +1795,6 @@ public extension %(class_name)s { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: %s.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(%s.databaseTableName) WHERE \(%sColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] @@ -1822,7 +1802,7 @@ public extension %(class_name)s { } } } -''' % ( str(clazz.name), record_name, str(clazz.name), record_name, record_identifier(clazz.name), ) +''' % ( record_name, record_name, record_identifier(clazz.name), ) # ---- Fetch ---- diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index c4aa378331..ec63842947 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -38,7 +38,6 @@ 3405C06E25435048008B24EF /* ConversationViewController+Banners.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3405C06D25435048008B24EF /* ConversationViewController+Banners.swift */; }; 34074F61203D0CBE004596AE /* OWSSounds.m in Sources */ = {isa = PBXBuildFile; fileRef = 34074F5F203D0CBD004596AE /* OWSSounds.m */; }; 34074F62203D0CBE004596AE /* OWSSounds.h in Headers */ = {isa = PBXBuildFile; fileRef = 34074F60203D0CBE004596AE /* OWSSounds.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 34080E4022E9F50200B4D9DA /* YDBToGRDBMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34080E3F22E9F50200B4D9DA /* YDBToGRDBMigration.swift */; }; 34080EFE2225F96D0087E99F /* ImageEditorPaletteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34080EFD2225F96D0087E99F /* ImageEditorPaletteView.swift */; }; 34080F02222853E30087E99F /* ImageEditorBrushViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34080F01222853E30087E99F /* ImageEditorBrushViewController.swift */; }; 34080F04222858DC0087E99F /* OWSViewController+ImageEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34080F03222858DC0087E99F /* OWSViewController+ImageEditor.swift */; }; @@ -55,9 +54,6 @@ 340872DA22397FEB00CB25B0 /* AttachmentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340872D922397FEB00CB25B0 /* AttachmentTextView.swift */; }; 340B06C723C8DA2600929588 /* StorageService+GroupsV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340B06C623C8DA2600929588 /* StorageService+GroupsV2.swift */; }; 340B870E23DF3E3A00BE0AFC /* GroupV2UpdatesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340B870D23DF3E3A00BE0AFC /* GroupV2UpdatesImpl.swift */; }; - 340CCB6A23032762005243B3 /* YDBLegacyMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 340CCB6823032762005243B3 /* YDBLegacyMigration.m */; }; - 340CCB712305962B005243B3 /* YDBToGRDBMigrationKeyValueTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340CCB6F2305962A005243B3 /* YDBToGRDBMigrationKeyValueTest.swift */; }; - 340CCB722305962B005243B3 /* YDBToGRDBMigrationModelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340CCB702305962B005243B3 /* YDBToGRDBMigrationModelTest.swift */; }; 340D900024FEE6A9007B5504 /* GroupInviteLinksUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340D8FFF24FEE6A9007B5504 /* GroupInviteLinksUI.swift */; }; 340FC8AB204DAC8D007AEB0F /* DomainFrontingCountryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC87D204DAC8C007AEB0F /* DomainFrontingCountryViewController.m */; }; 340FC8AF204DAC8D007AEB0F /* OWSLinkDeviceViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC885204DAC8C007AEB0F /* OWSLinkDeviceViewController.m */; }; @@ -139,8 +135,6 @@ 3461293A1FD1B47300532771 /* OWSPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129381FD1B47200532771 /* OWSPreferences.m */; }; 3461295A1FD1D74C00532771 /* Environment.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129401FD1D74B00532771 /* Environment.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3461295B1FD1D74C00532771 /* Environment.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129411FD1D74B00532771 /* Environment.m */; }; - 346129951FD1E30000532771 /* OWSDatabaseMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129931FD1E30000532771 /* OWSDatabaseMigration.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 346129961FD1E30000532771 /* OWSDatabaseMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129941FD1E30000532771 /* OWSDatabaseMigration.m */; }; 346129991FD1E4DA00532771 /* SignalApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129971FD1E4D900532771 /* SignalApp.m */; }; 346129A51FD1F09100532771 /* OWSContactsManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129A21FD1F09100532771 /* OWSContactsManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 346129A61FD1F09100532771 /* OWSContactsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129A31FD1F09100532771 /* OWSContactsManager.m */; }; @@ -152,21 +146,6 @@ 346129D61FD20ADC00532771 /* UIViewController+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129D41FD20ADC00532771 /* UIViewController+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 346129E21FD5C0BE00532771 /* VersionMigrations.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129E01FD5C0BE00532771 /* VersionMigrations.h */; settings = {ATTRIBUTES = (Public, ); }; }; 346129E31FD5C0BE00532771 /* VersionMigrations.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129E11FD5C0BE00532771 /* VersionMigrations.m */; }; - 346129E61FD5C0C600532771 /* OWSDatabaseMigrationRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129E41FD5C0C600532771 /* OWSDatabaseMigrationRunner.m */; }; - 346129E71FD5C0C600532771 /* OWSDatabaseMigrationRunner.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129E51FD5C0C600532771 /* OWSDatabaseMigrationRunner.h */; }; - 346129F51FD5F31400532771 /* OWS102MoveLoggingPreferenceToUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129E81FD5F31200532771 /* OWS102MoveLoggingPreferenceToUserDefaults.m */; }; - 346129F61FD5F31400532771 /* OWS103EnableVideoCalling.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129E91FD5F31300532771 /* OWS103EnableVideoCalling.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 346129F71FD5F31400532771 /* OWS105AttachmentFilePaths.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129EA1FD5F31300532771 /* OWS105AttachmentFilePaths.m */; }; - 346129F81FD5F31400532771 /* OWS100RemoveTSRecipientsMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129EB1FD5F31300532771 /* OWS100RemoveTSRecipientsMigration.m */; }; - 346129F91FD5F31400532771 /* OWS104CreateRecipientIdentities.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129EC1FD5F31300532771 /* OWS104CreateRecipientIdentities.m */; }; - 346129FA1FD5F31400532771 /* OWS100RemoveTSRecipientsMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129ED1FD5F31300532771 /* OWS100RemoveTSRecipientsMigration.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 346129FB1FD5F31400532771 /* OWS101ExistingUsersBlockOnIdentityChange.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129EE1FD5F31300532771 /* OWS101ExistingUsersBlockOnIdentityChange.m */; }; - 346129FC1FD5F31400532771 /* OWS101ExistingUsersBlockOnIdentityChange.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129EF1FD5F31400532771 /* OWS101ExistingUsersBlockOnIdentityChange.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 346129FD1FD5F31400532771 /* OWS102MoveLoggingPreferenceToUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129F01FD5F31400532771 /* OWS102MoveLoggingPreferenceToUserDefaults.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 346129FE1FD5F31400532771 /* OWS106EnsureProfileComplete.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346129F11FD5F31400532771 /* OWS106EnsureProfileComplete.swift */; }; - 346129FF1FD5F31400532771 /* OWS103EnableVideoCalling.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129F21FD5F31400532771 /* OWS103EnableVideoCalling.m */; }; - 34612A001FD5F31400532771 /* OWS105AttachmentFilePaths.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129F31FD5F31400532771 /* OWS105AttachmentFilePaths.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 34612A011FD5F31400532771 /* OWS104CreateRecipientIdentities.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129F41FD5F31400532771 /* OWS104CreateRecipientIdentities.h */; settings = {ATTRIBUTES = (Public, ); }; }; 34612A061FD7238600532771 /* OWSSyncManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 34612A041FD7238500532771 /* OWSSyncManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 34612A071FD7238600532771 /* OWSSyncManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 34612A051FD7238500532771 /* OWSSyncManager.m */; }; 34635330256EA52A003C5428 /* ConversationViewTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3463532E256EA525003C5428 /* ConversationViewTest.swift */; }; @@ -193,7 +172,6 @@ 346941A3215D2EE400B5BFAD /* Theme.m in Sources */ = {isa = PBXBuildFile; fileRef = 3469419F215D2EE400B5BFAD /* Theme.m */; }; 346941A4215D2EE400B5BFAD /* OWSConversationColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 346941A0215D2EE400B5BFAD /* OWSConversationColor.h */; settings = {ATTRIBUTES = (Public, ); }; }; 346B4A772369BFC600B56007 /* PermissiveGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346B4A762369BFC600B56007 /* PermissiveGestureRecognizer.swift */; }; - 346B4A79236A138C00B56007 /* OWS116UpdatePrekeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346B4A78236A138C00B56007 /* OWS116UpdatePrekeys.swift */; }; 346B66311F4E29B200E5122F /* CropScaleImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */; }; 346C19DF25ACDF0B00061D3A /* DataSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346C19DE25ACDF0B00061D3A /* DataSettingsTableViewController.swift */; }; 346C19E125ACE9AE00061D3A /* MediaDownloadSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346C19E025ACE9AE00061D3A /* MediaDownloadSettingsViewController.swift */; }; @@ -277,6 +255,7 @@ 3491D9A121022DB7001EF5A1 /* RemoteAttestationSigningCertificateTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 3491D9A021022DB7001EF5A1 /* RemoteAttestationSigningCertificateTest.m */; }; 349439D624360C30001045F7 /* AddGroupMembersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349439D524360C30001045F7 /* AddGroupMembersViewController.swift */; }; 349439D824360D63001045F7 /* BaseGroupMemberViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349439D724360D63001045F7 /* BaseGroupMemberViewController.swift */; }; + 34955A73260A366600F3789A /* OnboardingDroppedYdbViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34955A72260A366600F3789A /* OnboardingDroppedYdbViewController.swift */; }; 3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3496744E2076ACCE00080B5F /* LongTextViewController.swift */; }; 3496955C219B605E00DCFE74 /* ImagePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34969559219B605E00DCFE74 /* ImagePickerController.swift */; }; 3496955D219B605E00DCFE74 /* PhotoCollectionPickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3496955A219B605E00DCFE74 /* PhotoCollectionPickerController.swift */; }; @@ -294,7 +273,6 @@ 349A5C5425CD7A6C00B30EE8 /* DebugContactsUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349A5C5325CD7A6C00B30EE8 /* DebugContactsUtils.swift */; }; 349BC861253A2651003C949A /* GroupsV2MigrationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349BC860253A2651003C949A /* GroupsV2MigrationTest.swift */; }; 349C3637233D198300D52012 /* LaunchJobs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349C3636233D198300D52012 /* LaunchJobs.swift */; }; - 349EA07C2162AEA800F7B17F /* OWS111UDAttributesMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */; }; 349ED990221B0194008045B0 /* Onboarding2FAViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349ED98F221B0194008045B0 /* Onboarding2FAViewController.swift */; }; 349ED992221EE80D008045B0 /* AppPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349ED991221EE80D008045B0 /* AppPreferences.swift */; }; 34A17D81253F7237009F8C02 /* ConversationSettingsViewController+LegacyGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A17D80253F7236009F8C02 /* ConversationSettingsViewController+LegacyGroups.swift */; }; @@ -302,8 +280,6 @@ 34A4D56F24E4D342002F8044 /* UnfairLockPerformanceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A4D56E24E4D341002F8044 /* UnfairLockPerformanceTest.swift */; }; 34A6C28021E503E700B5B12E /* OWSImagePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */; }; 34A8B3512190A40E00218A25 /* CVMediaAlbumView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A8B3502190A40E00218A25 /* CVMediaAlbumView.swift */; }; - 34ABB2C42090C59700C727A6 /* OWSResaveCollectionDBMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 34ABB2C22090C59600C727A6 /* OWSResaveCollectionDBMigration.m */; }; - 34ABB2C52090C59700C727A6 /* OWSResaveCollectionDBMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = 34ABB2C32090C59700C727A6 /* OWSResaveCollectionDBMigration.h */; settings = {ATTRIBUTES = (Public, ); }; }; 34AC09DD211B39B100997B47 /* ViewControllerUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 34AC09BF211B39AE00997B47 /* ViewControllerUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; 34AC09DE211B39B100997B47 /* OWSNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 34AC09C0211B39AE00997B47 /* OWSNavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 34AC09DF211B39B100997B47 /* OWSNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34AC09C1211B39AF00997B47 /* OWSNavigationController.m */; }; @@ -353,7 +329,6 @@ 34B3F8801E8DF1700035BE1A /* InviteFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F84C1E8DF1700035BE1A /* InviteFlow.swift */; }; 34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */; }; 34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */; }; - 34B6A909218B8824007C4606 /* OWS112TypingIndicatorsMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A908218B8824007C4606 /* OWS112TypingIndicatorsMigration.swift */; }; 34BB3C5D23C6644B001651FC /* GroupsV2Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BB3C5823C6644B001651FC /* GroupsV2Utils.swift */; }; 34BB3C5E23C6644B001651FC /* GroupsV2OutgoingChangesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BB3C5923C6644B001651FC /* GroupsV2OutgoingChangesImpl.swift */; }; 34BB3C5F23C6644B001651FC /* GroupV2SnapshotImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BB3C5A23C6644B001651FC /* GroupV2SnapshotImpl.swift */; }; @@ -373,7 +348,6 @@ 34BECE2B1F74C12700D7438D /* DebugUIStress.m in Sources */ = {isa = PBXBuildFile; fileRef = 34BECE2A1F74C12700D7438D /* DebugUIStress.m */; }; 34BECE2E1F7ABCE000D7438D /* GifPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BECE2D1F7ABCE000D7438D /* GifPickerViewController.swift */; }; 34BECE301F7ABCF800D7438D /* GifPickerLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BECE2F1F7ABCF800D7438D /* GifPickerLayout.swift */; }; - 34BEDB0B21C2FA3D007B0EAE /* OWS114RemoveDynamicInteractions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BEDB0A21C2FA3D007B0EAE /* OWS114RemoveDynamicInteractions.swift */; }; 34BEDB0E21C405B0007B0EAE /* ImageEditorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BEDB0D21C405B0007B0EAE /* ImageEditorModel.swift */; }; 34BEDB1321C43F6A007B0EAE /* ImageEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BEDB1221C43F69007B0EAE /* ImageEditorView.swift */; }; 34BEDB1621C80BCA007B0EAE /* OWSAnyTouchGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 34BEDB1421C80BC9007B0EAE /* OWSAnyTouchGestureRecognizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -405,15 +379,12 @@ 34D2CCE0206939B400CB1A14 /* DebugUIMessagesAssetLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCDC206939B200CB1A14 /* DebugUIMessagesAssetLoader.m */; }; 34D3E57B245A189D00F5E4A1 /* DebugUIScreenshots.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D3E579245A189D00F5E4A1 /* DebugUIScreenshots.swift */; }; 34D3E57C245A189D00F5E4A1 /* DebugUIScreenshots.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D3E57A245A189D00F5E4A1 /* DebugUIScreenshots.m */; }; - 34D5872F208E2C4200D2255A /* OWS109OutgoingMessageState.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5872D208E2C4100D2255A /* OWS109OutgoingMessageState.m */; }; - 34D58730208E2C4200D2255A /* OWS109OutgoingMessageState.h in Headers */ = {isa = PBXBuildFile; fileRef = 34D5872E208E2C4100D2255A /* OWS109OutgoingMessageState.h */; settings = {ATTRIBUTES = (Public, ); }; }; 34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */; }; 34D8C0271ED3673300188D7C /* DebugUIMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0241ED3673300188D7C /* DebugUIMessages.m */; }; 34D8C0281ED3673300188D7C /* DebugUITableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0261ED3673300188D7C /* DebugUITableViewController.m */; }; 34D8C02B1ED3685800188D7C /* DebugUIContacts.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C02A1ED3685800188D7C /* DebugUIContacts.m */; }; 34D99C931F2937CC00D284D6 /* OWSAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */; }; 34D99CE4217509C2000AFB39 /* AppEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D99CE3217509C1000AFB39 /* AppEnvironment.swift */; }; - 34DB0BED2011548B007B313F /* OWSDatabaseConverterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DB0BEC2011548B007B313F /* OWSDatabaseConverterTest.m */; }; 34DC9BD921543E0C00FDDCEC /* DebugContactsUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DC9BD721543E0A00FDDCEC /* DebugContactsUtils.m */; }; 34DE9C02256575300080E4AF /* CVMessageMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34DE9C012565752F0080E4AF /* CVMessageMapping.swift */; }; 34E0127423FDA960002D0D13 /* DebugUIGroupsV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E0127323FDA960002D0D13 /* DebugUIGroupsV2.swift */; }; @@ -432,8 +403,6 @@ 34FDB29221FF986600A01202 /* UIView+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FDB29121FF986600A01202 /* UIView+OWS.swift */; }; 4503F1BE20470A5B00CEE724 /* classic-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */; }; 4503F1BF20470A5B00CEE724 /* classic.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BC20470A5B00CEE724 /* classic.aifc */; }; - 4503F1C3204711D300CEE724 /* OWS107LegacySounds.m in Sources */ = {isa = PBXBuildFile; fileRef = 4503F1C1204711D200CEE724 /* OWS107LegacySounds.m */; }; - 4503F1C4204711D300CEE724 /* OWS107LegacySounds.h in Headers */ = {isa = PBXBuildFile; fileRef = 4503F1C2204711D200CEE724 /* OWS107LegacySounds.h */; settings = {ATTRIBUTES = (Public, ); }; }; 450998651FD8A34D00D89EB3 /* DeviceSleepManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348F2EAD1F0D21BC00D4ECE0 /* DeviceSleepManager.swift */; }; 450998681FD8C0FF00D89EB3 /* AttachmentSharing.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F83A1E8DF1700035BE1A /* AttachmentSharing.m */; }; 450998691FD8C10200D89EB3 /* AttachmentSharing.h in Headers */ = {isa = PBXBuildFile; fileRef = 34B3F8391E8DF1700035BE1A /* AttachmentSharing.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -492,8 +461,6 @@ 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */; }; 458E383A1D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38391D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m */; }; 459311FC1D75C948008DD4F0 /* OWSDeviceTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */; }; - 4598198E204E2F28009414F2 /* OWS108CallLoggingPreference.h in Headers */ = {isa = PBXBuildFile; fileRef = 4598198C204E2F28009414F2 /* OWS108CallLoggingPreference.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4598198F204E2F28009414F2 /* OWS108CallLoggingPreference.m in Sources */ = {isa = PBXBuildFile; fileRef = 4598198D204E2F28009414F2 /* OWS108CallLoggingPreference.m */; }; 459B775C207BA46C0071D0AB /* OWSQuotedReplyModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 459B775A207BA3A80071D0AB /* OWSQuotedReplyModel.m */; }; 459B775D207BA4810071D0AB /* OWSQuotedReplyModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 459B7759207BA3A80071D0AB /* OWSQuotedReplyModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; 45A2F005204473A3002E978A /* NewMessage.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 45A2F004204473A3002E978A /* NewMessage.aifc */; }; @@ -590,7 +557,6 @@ 4C38E500230374D700E464B9 /* UIViewController+Permissions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C38E4FE230374D700E464B9 /* UIViewController+Permissions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4C38E501230374D700E464B9 /* UIViewController+Permissions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C38E4FF230374D700E464B9 /* UIViewController+Permissions.m */; }; 4C3A2BC72356620E004B3986 /* ProvisioningController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A2BC62356620E004B3986 /* ProvisioningController.swift */; }; - 4C3A556F228C7937000E4935 /* PrivateMethodsForMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3A556E228C7937000E4935 /* PrivateMethodsForMigration.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4C3E245C21F29FCE000AE092 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA5F792211E1F06008C2708 /* Toast.swift */; }; 4C3E245D21F2B395000AE092 /* DirectionalPanGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4523149F1F7E9E18003A428C /* DirectionalPanGestureRecognizer.swift */; }; 4C3EF7FD2107DDEE0007EBF7 /* ParamParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3EF7FC2107DDEE0007EBF7 /* ParamParserTest.swift */; }; @@ -612,14 +578,12 @@ 4C6E6C6924241C00009DE948 /* ConversationViewControllerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6E6C6824241C00009DE948 /* ConversationViewControllerTest.swift */; }; 4C6F527C20FFE8400097DEEE /* SignalUBSan.supp in Resources */ = {isa = PBXBuildFile; fileRef = 4C6F527B20FFE8400097DEEE /* SignalUBSan.supp */; }; 4C751BE523FA0284002A8AF1 /* ContactSupportAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C751BE423FA0284002A8AF1 /* ContactSupportAlert.swift */; }; - 4C7537892193779700DF5E37 /* OWS113MultiAttachmentMediaMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7537882193779700DF5E37 /* OWS113MultiAttachmentMediaMessages.swift */; }; 4C81DAD5242051C100F4C4D1 /* MessageSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C81DAD4242051C100F4C4D1 /* MessageSelectionView.swift */; }; 4C83AC4223C55D9C00D4F2E6 /* SignalBaseTest+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C83AC4123C55D9C00D4F2E6 /* SignalBaseTest+Swift.swift */; }; 4C858A52212DC5E1001B45D3 /* UIImage+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C858A51212DC5E1001B45D3 /* UIImage+OWS.swift */; }; 4C8A6DFC22E5499300469AE7 /* MediaZoomAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C8A6DFB22E5499300469AE7 /* MediaZoomAnimationController.swift */; }; 4C8A6DFE22E54AFA00469AE7 /* MediaInteractiveDismiss.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C8A6DFD22E54AFA00469AE7 /* MediaInteractiveDismiss.swift */; }; 4C948FF72146EB4800349F0D /* BlockListCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C948FF62146EB4800349F0D /* BlockListCache.swift */; }; - 4C9B4F23225025F100DD5B9A /* OWS1XXGRDBMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9B4F22225025F100DD5B9A /* OWS1XXGRDBMigration.swift */; }; 4C9C50FE22F36FA50054A33F /* OutboundMessage+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9C50FD22F36FA40054A33F /* OutboundMessage+OWS.swift */; }; 4C9D347B23679C25006A4307 /* GroupAndContactStreamTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9D347923679C13006A4307 /* GroupAndContactStreamTest.swift */; }; 4C9D347F23689E06006A4307 /* IncomingContactSyncJobQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9D347E23689E06006A4307 /* IncomingContactSyncJobQueue.swift */; }; @@ -633,9 +597,7 @@ 4CB5F26720F6E1E2004D1B42 /* MessageActionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF4C0920F55BBA005DA313 /* MessageActionsViewController.swift */; }; 4CB5F26920F7D060004D1B42 /* MessageActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB5F26820F7D060004D1B42 /* MessageActions.swift */; }; 4CB93DC22180FF07004B9764 /* ProximityMonitoringManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB93DC12180FF07004B9764 /* ProximityMonitoringManager.swift */; }; - 4CBBCA6321714B4500EEB37D /* OWS110SortIdMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CBBCA6221714B4500EEB37D /* OWS110SortIdMigration.swift */; }; 4CBBFE4A2306F5D300B37450 /* LogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CBBFE492306F5D300B37450 /* LogViewController.swift */; }; - 4CBF6F7B230B03C000549FFC /* OWS115CleanupProfileAvatars.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CBF6F7A230B03C000549FFC /* OWS115CleanupProfileAvatars.swift */; }; 4CC0B59C20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */; }; 4CC1ECF9211A47CE00CC13BE /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC1ECF8211A47CD00CC13BE /* StoreKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */; }; @@ -1011,7 +973,6 @@ 3405C06D25435048008B24EF /* ConversationViewController+Banners.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConversationViewController+Banners.swift"; sourceTree = ""; }; 34074F5F203D0CBD004596AE /* OWSSounds.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSSounds.m; sourceTree = ""; }; 34074F60203D0CBE004596AE /* OWSSounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSSounds.h; sourceTree = ""; }; - 34080E3F22E9F50200B4D9DA /* YDBToGRDBMigration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = YDBToGRDBMigration.swift; sourceTree = ""; }; 34080EFD2225F96D0087E99F /* ImageEditorPaletteView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageEditorPaletteView.swift; sourceTree = ""; }; 34080F01222853E30087E99F /* ImageEditorBrushViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageEditorBrushViewController.swift; sourceTree = ""; }; 34080F03222858DC0087E99F /* OWSViewController+ImageEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OWSViewController+ImageEditor.swift"; sourceTree = ""; }; @@ -1029,10 +990,6 @@ 340B02B61F9FD31800F9CFEC /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = translations/he.lproj/Localizable.strings; sourceTree = ""; }; 340B06C623C8DA2600929588 /* StorageService+GroupsV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "StorageService+GroupsV2.swift"; sourceTree = ""; }; 340B870D23DF3E3A00BE0AFC /* GroupV2UpdatesImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupV2UpdatesImpl.swift; sourceTree = ""; }; - 340CCB6823032762005243B3 /* YDBLegacyMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YDBLegacyMigration.m; sourceTree = ""; }; - 340CCB6923032762005243B3 /* YDBLegacyMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YDBLegacyMigration.h; sourceTree = ""; }; - 340CCB6F2305962A005243B3 /* YDBToGRDBMigrationKeyValueTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = YDBToGRDBMigrationKeyValueTest.swift; sourceTree = ""; }; - 340CCB702305962B005243B3 /* YDBToGRDBMigrationModelTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = YDBToGRDBMigrationModelTest.swift; sourceTree = ""; }; 340D8FFF24FEE6A9007B5504 /* GroupInviteLinksUI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupInviteLinksUI.swift; sourceTree = ""; }; 340E9ABF235F876800FA362C /* ForwardMessageNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForwardMessageNavigationController.swift; sourceTree = ""; }; 340E9AC3236095CC00FA362C /* AttachmentMultisend.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentMultisend.swift; sourceTree = ""; }; @@ -1140,8 +1097,6 @@ 346129381FD1B47200532771 /* OWSPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSPreferences.m; sourceTree = ""; }; 346129401FD1D74B00532771 /* Environment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Environment.h; sourceTree = ""; }; 346129411FD1D74B00532771 /* Environment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Environment.m; sourceTree = ""; }; - 346129931FD1E30000532771 /* OWSDatabaseMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDatabaseMigration.h; sourceTree = ""; }; - 346129941FD1E30000532771 /* OWSDatabaseMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDatabaseMigration.m; sourceTree = ""; }; 346129971FD1E4D900532771 /* SignalApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalApp.m; sourceTree = ""; }; 346129981FD1E4DA00532771 /* SignalApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalApp.h; sourceTree = ""; }; 346129A21FD1F09100532771 /* OWSContactsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactsManager.h; sourceTree = ""; }; @@ -1156,21 +1111,6 @@ 346129D41FD20ADC00532771 /* UIViewController+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+OWS.h"; sourceTree = ""; }; 346129E01FD5C0BE00532771 /* VersionMigrations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VersionMigrations.h; sourceTree = ""; }; 346129E11FD5C0BE00532771 /* VersionMigrations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VersionMigrations.m; sourceTree = ""; }; - 346129E41FD5C0C600532771 /* OWSDatabaseMigrationRunner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDatabaseMigrationRunner.m; sourceTree = ""; }; - 346129E51FD5C0C600532771 /* OWSDatabaseMigrationRunner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDatabaseMigrationRunner.h; sourceTree = ""; }; - 346129E81FD5F31200532771 /* OWS102MoveLoggingPreferenceToUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS102MoveLoggingPreferenceToUserDefaults.m; sourceTree = ""; }; - 346129E91FD5F31300532771 /* OWS103EnableVideoCalling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS103EnableVideoCalling.h; sourceTree = ""; }; - 346129EA1FD5F31300532771 /* OWS105AttachmentFilePaths.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS105AttachmentFilePaths.m; sourceTree = ""; }; - 346129EB1FD5F31300532771 /* OWS100RemoveTSRecipientsMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS100RemoveTSRecipientsMigration.m; sourceTree = ""; }; - 346129EC1FD5F31300532771 /* OWS104CreateRecipientIdentities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS104CreateRecipientIdentities.m; sourceTree = ""; }; - 346129ED1FD5F31300532771 /* OWS100RemoveTSRecipientsMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS100RemoveTSRecipientsMigration.h; sourceTree = ""; }; - 346129EE1FD5F31300532771 /* OWS101ExistingUsersBlockOnIdentityChange.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS101ExistingUsersBlockOnIdentityChange.m; sourceTree = ""; }; - 346129EF1FD5F31400532771 /* OWS101ExistingUsersBlockOnIdentityChange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS101ExistingUsersBlockOnIdentityChange.h; sourceTree = ""; }; - 346129F01FD5F31400532771 /* OWS102MoveLoggingPreferenceToUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS102MoveLoggingPreferenceToUserDefaults.h; sourceTree = ""; }; - 346129F11FD5F31400532771 /* OWS106EnsureProfileComplete.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS106EnsureProfileComplete.swift; sourceTree = ""; }; - 346129F21FD5F31400532771 /* OWS103EnableVideoCalling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS103EnableVideoCalling.m; sourceTree = ""; }; - 346129F31FD5F31400532771 /* OWS105AttachmentFilePaths.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS105AttachmentFilePaths.h; sourceTree = ""; }; - 346129F41FD5F31400532771 /* OWS104CreateRecipientIdentities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS104CreateRecipientIdentities.h; sourceTree = ""; }; 34612A041FD7238500532771 /* OWSSyncManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSSyncManager.h; sourceTree = ""; }; 34612A051FD7238500532771 /* OWSSyncManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSSyncManager.m; sourceTree = ""; }; 3463532E256EA525003C5428 /* ConversationViewTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConversationViewTest.swift; sourceTree = ""; }; @@ -1200,7 +1140,6 @@ 3469419F215D2EE400B5BFAD /* Theme.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Theme.m; sourceTree = ""; }; 346941A0215D2EE400B5BFAD /* OWSConversationColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSConversationColor.h; sourceTree = ""; }; 346B4A762369BFC600B56007 /* PermissiveGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissiveGestureRecognizer.swift; sourceTree = ""; }; - 346B4A78236A138C00B56007 /* OWS116UpdatePrekeys.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS116UpdatePrekeys.swift; sourceTree = ""; }; 346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CropScaleImageViewController.swift; sourceTree = ""; }; 346C19DE25ACDF0B00061D3A /* DataSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataSettingsTableViewController.swift; sourceTree = ""; }; 346C19E025ACE9AE00061D3A /* MediaDownloadSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaDownloadSettingsViewController.swift; sourceTree = ""; }; @@ -1286,6 +1225,7 @@ 3491D9A021022DB7001EF5A1 /* RemoteAttestationSigningCertificateTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RemoteAttestationSigningCertificateTest.m; sourceTree = ""; }; 349439D524360C30001045F7 /* AddGroupMembersViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddGroupMembersViewController.swift; sourceTree = ""; }; 349439D724360D63001045F7 /* BaseGroupMemberViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseGroupMemberViewController.swift; sourceTree = ""; }; + 34955A72260A366600F3789A /* OnboardingDroppedYdbViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingDroppedYdbViewController.swift; sourceTree = ""; }; 3495BC911F1426B800B478F5 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = translations/ar.lproj/Localizable.strings; sourceTree = ""; }; 3495FF1325F9A0C900959D6E /* ug */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ug; path = translations/ug.lproj/InfoPlist.strings; sourceTree = ""; }; 3495FF1425F9A0C900959D6E /* ug */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ug; path = translations/ug.lproj/Localizable.strings; sourceTree = ""; }; @@ -1306,7 +1246,6 @@ 349A5C5325CD7A6C00B30EE8 /* DebugContactsUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugContactsUtils.swift; sourceTree = ""; }; 349BC860253A2651003C949A /* GroupsV2MigrationTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupsV2MigrationTest.swift; sourceTree = ""; }; 349C3636233D198300D52012 /* LaunchJobs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LaunchJobs.swift; sourceTree = ""; }; - 349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS111UDAttributesMigration.swift; sourceTree = ""; }; 349ED98F221B0194008045B0 /* Onboarding2FAViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Onboarding2FAViewController.swift; sourceTree = ""; }; 349ED991221EE80D008045B0 /* AppPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppPreferences.swift; sourceTree = ""; }; 34A17D80253F7236009F8C02 /* ConversationSettingsViewController+LegacyGroups.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConversationSettingsViewController+LegacyGroups.swift"; sourceTree = ""; }; @@ -1314,8 +1253,6 @@ 34A4D56E24E4D341002F8044 /* UnfairLockPerformanceTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnfairLockPerformanceTest.swift; sourceTree = ""; }; 34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSImagePickerController.swift; sourceTree = ""; }; 34A8B3502190A40E00218A25 /* CVMediaAlbumView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CVMediaAlbumView.swift; sourceTree = ""; }; - 34ABB2C22090C59600C727A6 /* OWSResaveCollectionDBMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSResaveCollectionDBMigration.m; sourceTree = ""; }; - 34ABB2C32090C59700C727A6 /* OWSResaveCollectionDBMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSResaveCollectionDBMigration.h; sourceTree = ""; }; 34AC09BF211B39AE00997B47 /* ViewControllerUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewControllerUtils.h; sourceTree = ""; }; 34AC09C0211B39AE00997B47 /* OWSNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSNavigationController.h; sourceTree = ""; }; 34AC09C1211B39AF00997B47 /* OWSNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSNavigationController.m; sourceTree = ""; }; @@ -1369,7 +1306,6 @@ 34B3F84C1E8DF1700035BE1A /* InviteFlow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InviteFlow.swift; sourceTree = ""; }; 34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorView.swift; sourceTree = ""; }; 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorInteraction.swift; sourceTree = ""; }; - 34B6A908218B8824007C4606 /* OWS112TypingIndicatorsMigration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS112TypingIndicatorsMigration.swift; sourceTree = ""; }; 34BB3C5823C6644B001651FC /* GroupsV2Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupsV2Utils.swift; sourceTree = ""; }; 34BB3C5923C6644B001651FC /* GroupsV2OutgoingChangesImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupsV2OutgoingChangesImpl.swift; sourceTree = ""; }; 34BB3C5A23C6644B001651FC /* GroupV2SnapshotImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupV2SnapshotImpl.swift; sourceTree = ""; }; @@ -1390,7 +1326,6 @@ 34BECE2A1F74C12700D7438D /* DebugUIStress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIStress.m; sourceTree = ""; }; 34BECE2D1F7ABCE000D7438D /* GifPickerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GifPickerViewController.swift; sourceTree = ""; }; 34BECE2F1F7ABCF800D7438D /* GifPickerLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GifPickerLayout.swift; sourceTree = ""; }; - 34BEDB0A21C2FA3D007B0EAE /* OWS114RemoveDynamicInteractions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS114RemoveDynamicInteractions.swift; sourceTree = ""; }; 34BEDB0D21C405B0007B0EAE /* ImageEditorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageEditorModel.swift; sourceTree = ""; }; 34BEDB1221C43F69007B0EAE /* ImageEditorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageEditorView.swift; sourceTree = ""; }; 34BEDB1421C80BC9007B0EAE /* OWSAnyTouchGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAnyTouchGestureRecognizer.h; sourceTree = ""; }; @@ -1431,8 +1366,6 @@ 34D3E578245A189D00F5E4A1 /* DebugUIScreenshots.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIScreenshots.h; sourceTree = ""; }; 34D3E579245A189D00F5E4A1 /* DebugUIScreenshots.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugUIScreenshots.swift; sourceTree = ""; }; 34D3E57A245A189D00F5E4A1 /* DebugUIScreenshots.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIScreenshots.m; sourceTree = ""; }; - 34D5872D208E2C4100D2255A /* OWS109OutgoingMessageState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS109OutgoingMessageState.m; sourceTree = ""; }; - 34D5872E208E2C4100D2255A /* OWS109OutgoingMessageState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS109OutgoingMessageState.h; sourceTree = ""; }; 34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvatarViewHelper.h; sourceTree = ""; }; 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AvatarViewHelper.m; sourceTree = ""; }; 34D8C0231ED3673300188D7C /* DebugUIMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMessages.h; sourceTree = ""; }; @@ -1444,7 +1377,6 @@ 34D913491F62D4A500722898 /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalAttachment.swift; sourceTree = ""; }; 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSAnalytics.swift; sourceTree = ""; }; 34D99CE3217509C1000AFB39 /* AppEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppEnvironment.swift; sourceTree = ""; }; - 34DB0BEC2011548B007B313F /* OWSDatabaseConverterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDatabaseConverterTest.m; sourceTree = ""; }; 34DBF001206BD5A500025978 /* OWSBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBubbleView.m; sourceTree = ""; }; 34DBF002206BD5A500025978 /* OWSBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBubbleView.h; sourceTree = ""; }; 34DBF005206C3CB100025978 /* OWSBubbleShapeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBubbleShapeView.h; sourceTree = ""; }; @@ -1477,8 +1409,6 @@ 435EAC2E5E22D3F087EB3192 /* Pods-SignalShareExtension.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalShareExtension.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalShareExtension/Pods-SignalShareExtension.app store release.xcconfig"; sourceTree = ""; }; 4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = "classic-quiet.aifc"; sourceTree = ""; }; 4503F1BC20470A5B00CEE724 /* classic.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = classic.aifc; sourceTree = ""; }; - 4503F1C1204711D200CEE724 /* OWS107LegacySounds.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS107LegacySounds.m; sourceTree = ""; }; - 4503F1C2204711D200CEE724 /* OWS107LegacySounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS107LegacySounds.h; sourceTree = ""; }; 4509E7991DD653700025A59F /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = ThirdParty/WebRTC/Build/WebRTC.framework; sourceTree = ""; }; 450D19111F85236600970622 /* RemoteVideoView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RemoteVideoView.h; sourceTree = ""; }; 450D19121F85236600970622 /* RemoteVideoView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RemoteVideoView.m; sourceTree = ""; }; @@ -1537,8 +1467,6 @@ 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceTableViewCell.m; sourceTree = ""; }; 4597E94E1D8313C100040CDE /* sq */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sq; path = translations/sq.lproj/Localizable.strings; sourceTree = ""; }; 4597E94F1D8313CB00040CDE /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = translations/bg.lproj/Localizable.strings; sourceTree = ""; }; - 4598198C204E2F28009414F2 /* OWS108CallLoggingPreference.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OWS108CallLoggingPreference.h; sourceTree = ""; }; - 4598198D204E2F28009414F2 /* OWS108CallLoggingPreference.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OWS108CallLoggingPreference.m; sourceTree = ""; }; 459B7759207BA3A80071D0AB /* OWSQuotedReplyModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OWSQuotedReplyModel.h; sourceTree = ""; }; 459B775A207BA3A80071D0AB /* OWSQuotedReplyModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OWSQuotedReplyModel.m; sourceTree = ""; }; 45A2F004204473A3002E978A /* NewMessage.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; name = NewMessage.aifc; path = Signal/AudioFiles/NewMessage.aifc; sourceTree = SOURCE_ROOT; }; @@ -1625,7 +1553,6 @@ 4C38E4FE230374D700E464B9 /* UIViewController+Permissions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+Permissions.h"; sourceTree = ""; }; 4C38E4FF230374D700E464B9 /* UIViewController+Permissions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+Permissions.m"; sourceTree = ""; }; 4C3A2BC62356620E004B3986 /* ProvisioningController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProvisioningController.swift; sourceTree = ""; }; - 4C3A556E228C7937000E4935 /* PrivateMethodsForMigration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PrivateMethodsForMigration.h; sourceTree = ""; }; 4C3EF7FC2107DDEE0007EBF7 /* ParamParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParamParserTest.swift; sourceTree = ""; }; 4C3EF801210918740007EBF7 /* SSKProtoEnvelopeTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSKProtoEnvelopeTest.swift; sourceTree = ""; }; 4C42960D2318E5EB00D9D240 /* MessageProcessingPerformanceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageProcessingPerformanceTest.swift; sourceTree = ""; }; @@ -1649,14 +1576,12 @@ 4C6E6C6824241C00009DE948 /* ConversationViewControllerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationViewControllerTest.swift; sourceTree = ""; }; 4C6F527B20FFE8400097DEEE /* SignalUBSan.supp */ = {isa = PBXFileReference; lastKnownFileType = text; path = SignalUBSan.supp; sourceTree = ""; }; 4C751BE423FA0284002A8AF1 /* ContactSupportAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportAlert.swift; sourceTree = ""; }; - 4C7537882193779700DF5E37 /* OWS113MultiAttachmentMediaMessages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWS113MultiAttachmentMediaMessages.swift; sourceTree = ""; }; 4C81DAD4242051C100F4C4D1 /* MessageSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSelectionView.swift; sourceTree = ""; }; 4C83AC4123C55D9C00D4F2E6 /* SignalBaseTest+Swift.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SignalBaseTest+Swift.swift"; sourceTree = ""; }; 4C858A51212DC5E1001B45D3 /* UIImage+OWS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+OWS.swift"; sourceTree = ""; }; 4C8A6DFB22E5499300469AE7 /* MediaZoomAnimationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaZoomAnimationController.swift; sourceTree = ""; }; 4C8A6DFD22E54AFA00469AE7 /* MediaInteractiveDismiss.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaInteractiveDismiss.swift; sourceTree = ""; }; 4C948FF62146EB4800349F0D /* BlockListCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockListCache.swift; sourceTree = ""; }; - 4C9B4F22225025F100DD5B9A /* OWS1XXGRDBMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWS1XXGRDBMigration.swift; sourceTree = ""; }; 4C9C50FD22F36FA40054A33F /* OutboundMessage+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OutboundMessage+OWS.swift"; sourceTree = ""; }; 4C9C50FF22F495F60054A33F /* BroadcastMediaMessageJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BroadcastMediaMessageJob.swift; sourceTree = ""; }; 4C9CA25C217E676900607C63 /* ZXingObjC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ZXingObjC.framework; path = ThirdParty/Carthage/Build/iOS/ZXingObjC.framework; sourceTree = ""; }; @@ -1672,9 +1597,7 @@ 4CA5F792211E1F06008C2708 /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = ""; }; 4CB5F26820F7D060004D1B42 /* MessageActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageActions.swift; sourceTree = ""; }; 4CB93DC12180FF07004B9764 /* ProximityMonitoringManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProximityMonitoringManager.swift; sourceTree = ""; }; - 4CBBCA6221714B4500EEB37D /* OWS110SortIdMigration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS110SortIdMigration.swift; sourceTree = ""; }; 4CBBFE492306F5D300B37450 /* LogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewController.swift; sourceTree = ""; }; - 4CBF6F7A230B03C000549FFC /* OWS115CleanupProfileAvatars.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWS115CleanupProfileAvatars.swift; sourceTree = ""; }; 4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationConfigurationSyncOperation.swift; sourceTree = ""; }; 4CC1ECF8211A47CD00CC13BE /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdateNag.swift; sourceTree = ""; }; @@ -2238,6 +2161,7 @@ 3448E1612213585C004B052E /* OnboardingBaseViewController.swift */, 3448E1652215B313004B052E /* OnboardingCaptchaViewController.swift */, 3448E15D221333F5004B052E /* OnboardingController.swift */, + 34955A72260A366600F3789A /* OnboardingDroppedYdbViewController.swift */, 88EAD79123764F09004B797E /* OnboardingModeSwitchConfirmationViewController.swift */, 3448E15B22133274004B052E /* OnboardingPermissionsViewController.swift */, 88D1BCBD24F75226009A1738 /* OnboardingPhoneNumberDiscoverabilityViewController.swift */, @@ -2468,7 +2392,6 @@ 346129411FD1D74B00532771 /* Environment.m */, 349C3636233D198300D52012 /* LaunchJobs.swift */, 4C35B08823F8A9A1003EB937 /* MessageRequestReadReceipts.swift */, - 346129921FD1E30000532771 /* migrations */, 347850671FD9B78A007B8332 /* NoopCallMessageHandler.swift */, 45F170AB1E2F0351003FC1F2 /* OWSAudioSession.swift */, 34074F60203D0CBE004596AE /* OWSSounds.h */, @@ -2479,48 +2402,6 @@ path = environment; sourceTree = ""; }; - 346129921FD1E30000532771 /* migrations */ = { - isa = PBXGroup; - children = ( - 4C9B4F22225025F100DD5B9A /* OWS1XXGRDBMigration.swift */, - 346129ED1FD5F31300532771 /* OWS100RemoveTSRecipientsMigration.h */, - 346129EB1FD5F31300532771 /* OWS100RemoveTSRecipientsMigration.m */, - 346129EF1FD5F31400532771 /* OWS101ExistingUsersBlockOnIdentityChange.h */, - 346129EE1FD5F31300532771 /* OWS101ExistingUsersBlockOnIdentityChange.m */, - 346129F01FD5F31400532771 /* OWS102MoveLoggingPreferenceToUserDefaults.h */, - 346129E81FD5F31200532771 /* OWS102MoveLoggingPreferenceToUserDefaults.m */, - 346129E91FD5F31300532771 /* OWS103EnableVideoCalling.h */, - 346129F21FD5F31400532771 /* OWS103EnableVideoCalling.m */, - 346129F41FD5F31400532771 /* OWS104CreateRecipientIdentities.h */, - 346129EC1FD5F31300532771 /* OWS104CreateRecipientIdentities.m */, - 346129F31FD5F31400532771 /* OWS105AttachmentFilePaths.h */, - 346129EA1FD5F31300532771 /* OWS105AttachmentFilePaths.m */, - 346129F11FD5F31400532771 /* OWS106EnsureProfileComplete.swift */, - 4503F1C2204711D200CEE724 /* OWS107LegacySounds.h */, - 4503F1C1204711D200CEE724 /* OWS107LegacySounds.m */, - 4598198C204E2F28009414F2 /* OWS108CallLoggingPreference.h */, - 4598198D204E2F28009414F2 /* OWS108CallLoggingPreference.m */, - 34D5872E208E2C4100D2255A /* OWS109OutgoingMessageState.h */, - 34D5872D208E2C4100D2255A /* OWS109OutgoingMessageState.m */, - 4CBBCA6221714B4500EEB37D /* OWS110SortIdMigration.swift */, - 349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */, - 34B6A908218B8824007C4606 /* OWS112TypingIndicatorsMigration.swift */, - 4C7537882193779700DF5E37 /* OWS113MultiAttachmentMediaMessages.swift */, - 34BEDB0A21C2FA3D007B0EAE /* OWS114RemoveDynamicInteractions.swift */, - 4CBF6F7A230B03C000549FFC /* OWS115CleanupProfileAvatars.swift */, - 346B4A78236A138C00B56007 /* OWS116UpdatePrekeys.swift */, - 346129931FD1E30000532771 /* OWSDatabaseMigration.h */, - 346129941FD1E30000532771 /* OWSDatabaseMigration.m */, - 346129E51FD5C0C600532771 /* OWSDatabaseMigrationRunner.h */, - 346129E41FD5C0C600532771 /* OWSDatabaseMigrationRunner.m */, - 34ABB2C32090C59700C727A6 /* OWSResaveCollectionDBMigration.h */, - 34ABB2C22090C59600C727A6 /* OWSResaveCollectionDBMigration.m */, - 4C3A556E228C7937000E4935 /* PrivateMethodsForMigration.h */, - 34080E3F22E9F50200B4D9DA /* YDBToGRDBMigration.swift */, - ); - path = migrations; - sourceTree = ""; - }; 346129A11FD1F09100532771 /* contacts */ = { isa = PBXGroup; children = ( @@ -3296,8 +3177,6 @@ 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */, FCFA64B11A24F29E0007FB87 /* UI Categories */, 8811CF832295D8DA00FF6549 /* VolumeButtons.swift */, - 340CCB6923032762005243B3 /* YDBLegacyMigration.h */, - 340CCB6823032762005243B3 /* YDBLegacyMigration.m */, ); path = util; sourceTree = ""; @@ -3832,7 +3711,6 @@ 345AE2B52317048200DB6225 /* GRDBFinderTest.swift */, 4C9D347923679C13006A4307 /* GroupAndContactStreamTest.swift */, 455AC69D1F4F8B0300134004 /* ImageCacheTest.swift */, - 34DB0BEC2011548B007B313F /* OWSDatabaseConverterTest.m */, 34843B25214327C9004DED45 /* OWSOrphanDataCleanerTest.m */, 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */, 34E8A8D02085238900B272B1 /* ProtoParsingTest.m */, @@ -3840,8 +3718,6 @@ 452D1AF02081059C00A67F7F /* StringAdditionsTest.swift */, B660F6B31C29868000687D6E /* UtilTest.h */, B660F6B41C29868000687D6E /* UtilTest.m */, - 340CCB6F2305962A005243B3 /* YDBToGRDBMigrationKeyValueTest.swift */, - 340CCB702305962B005243B3 /* YDBToGRDBMigrationModelTest.swift */, ); path = util; sourceTree = ""; @@ -3980,21 +3856,14 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 346129E71FD5C0C600532771 /* OWSDatabaseMigrationRunner.h in Headers */, 3464451222B7F97100A957B1 /* DateUtil.h in Headers */, 3464450E22B7F93600A957B1 /* OWSOrphanDataCleaner.h in Headers */, 34AC09F9211B39B100997B47 /* CountryCodeViewController.h in Headers */, - 34ABB2C52090C59700C727A6 /* OWSResaveCollectionDBMigration.h in Headers */, 8860CC1C25084BD400A4D18E /* OWSBubbleView.h in Headers */, 459B775D207BA4810071D0AB /* OWSQuotedReplyModel.h in Headers */, - 34612A001FD5F31400532771 /* OWS105AttachmentFilePaths.h in Headers */, - 346129F61FD5F31400532771 /* OWS103EnableVideoCalling.h in Headers */, - 4C3A556F228C7937000E4935 /* PrivateMethodsForMigration.h in Headers */, 34480B551FD0A7A400BC14EF /* DebugLogger.h in Headers */, - 4503F1C4204711D300CEE724 /* OWS107LegacySounds.h in Headers */, 34AC0A20211B39EA00997B47 /* ThreadViewHelper.h in Headers */, 34AC09DE211B39B100997B47 /* OWSNavigationController.h in Headers */, - 34612A011FD5F31400532771 /* OWS104CreateRecipientIdentities.h in Headers */, 450998691FD8C10200D89EB3 /* AttachmentSharing.h in Headers */, 34BEDB1621C80BCA007B0EAE /* OWSAnyTouchGestureRecognizer.h in Headers */, 34AC09EC211B39B100997B47 /* OWSTableViewController.h in Headers */, @@ -4003,24 +3872,19 @@ 3426A36E255EB9F50036407F /* CVItemViewModel.h in Headers */, 34612A061FD7238600532771 /* OWSSyncManager.h in Headers */, 34480B571FD0A7A400BC14EF /* OWSScrubbingLogFormatter.h in Headers */, - 346129FC1FD5F31400532771 /* OWS101ExistingUsersBlockOnIdentityChange.h in Headers */, 34AC09F2211B39B100997B47 /* OWSViewController.h in Headers */, 4C38E500230374D700E464B9 /* UIViewController+Permissions.h in Headers */, 451F8A491FD715CF005CB9DA /* OWSAvatarBuilder.h in Headers */, - 346129951FD1E30000532771 /* OWSDatabaseMigration.h in Headers */, 34AC09E4211B39B100997B47 /* ScreenLockViewController.h in Headers */, 346129B41FD1F7E800532771 /* OWSProfileManager.h in Headers */, 342950892124CB0A0000B063 /* OWSSearchBar.h in Headers */, 346941A1215D2EE400B5BFAD /* Theme.h in Headers */, - 346129FA1FD5F31400532771 /* OWS100RemoveTSRecipientsMigration.h in Headers */, 346129E21FD5C0BE00532771 /* VersionMigrations.h in Headers */, 453518961FC63DBF00210559 /* SignalMessaging.h in Headers */, 346941A4215D2EE400B5BFAD /* OWSConversationColor.h in Headers */, 3461295A1FD1D74C00532771 /* Environment.h in Headers */, 450C801020AD1AE400F3A091 /* OWSWindowManager.h in Headers */, - 34D58730208E2C4200D2255A /* OWS109OutgoingMessageState.h in Headers */, 8860CC1D25084BE700A4D18E /* OWSBubbleShapeView.h in Headers */, - 4598198E204E2F28009414F2 /* OWS108CallLoggingPreference.h in Headers */, 34AC0A0F211B39EA00997B47 /* ContactTableViewCell.h in Headers */, 34480B631FD0A98800BC14EF /* UIView+OWS.h in Headers */, 451F8A4B1FD715E1005CB9DA /* OWSGroupAvatarBuilder.h in Headers */, @@ -4039,7 +3903,6 @@ 34480B681FD0AA9400BC14EF /* UIFont+OWS.h in Headers */, 342950852124C9750000B063 /* OWSTextField.h in Headers */, 45194F901FD7200000333B2C /* ThreadUtil.h in Headers */, - 346129FD1FD5F31400532771 /* OWS102MoveLoggingPreferenceToUserDefaults.h in Headers */, 34074F62203D0CBE004596AE /* OWSSounds.h in Headers */, 34AC0A1D211B39EA00997B47 /* ContactCellView.h in Headers */, ); @@ -4610,7 +4473,6 @@ "${BUILT_PRODUCTS_DIR}/Starscream/Starscream.framework", "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework", "${BUILT_PRODUCTS_DIR}/YYImage/YYImage.framework", - "${BUILT_PRODUCTS_DIR}/YapDatabase/YapDatabase.framework", "${BUILT_PRODUCTS_DIR}/ZKGroup/ZKGroup.framework", "${PODS_ROOT}/ZXingObjC/ZXingObjC.framework", "${PODS_ROOT}/ZXingObjC/ZXingObjC.framework.dSYM", @@ -4644,7 +4506,6 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYImage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YapDatabase.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZKGroup.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZXingObjC.framework", "${DWARF_DSYM_FOLDER_PATH}/ZXingObjC.framework.dSYM", @@ -4706,7 +4567,6 @@ "${BUILT_PRODUCTS_DIR}/Starscream/Starscream.framework", "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework", "${BUILT_PRODUCTS_DIR}/YYImage/YYImage.framework", - "${BUILT_PRODUCTS_DIR}/YapDatabase/YapDatabase.framework", "${BUILT_PRODUCTS_DIR}/ZKGroup/ZKGroup.framework", "${PODS_ROOT}/ZXingObjC/ZXingObjC.framework", "${PODS_ROOT}/ZXingObjC/ZXingObjC.framework.dSYM", @@ -4737,7 +4597,6 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYImage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YapDatabase.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZKGroup.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZXingObjC.framework", "${DWARF_DSYM_FOLDER_PATH}/ZXingObjC.framework.dSYM", @@ -4796,7 +4655,6 @@ "${BUILT_PRODUCTS_DIR}/Starscream/Starscream.framework", "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework", "${BUILT_PRODUCTS_DIR}/YYImage/YYImage.framework", - "${BUILT_PRODUCTS_DIR}/YapDatabase/YapDatabase.framework", "${BUILT_PRODUCTS_DIR}/ZKGroup/ZKGroup.framework", "${PODS_ROOT}/ZXingObjC/ZXingObjC.framework", "${PODS_ROOT}/ZXingObjC/ZXingObjC.framework.dSYM", @@ -4827,7 +4685,6 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYImage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YapDatabase.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZKGroup.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZXingObjC.framework", "${DWARF_DSYM_FOLDER_PATH}/ZXingObjC.framework.dSYM", @@ -4920,11 +4777,8 @@ 4C9D347F23689E06006A4307 /* IncomingContactSyncJobQueue.swift in Sources */, 4C35B08A23F8A9D2003EB937 /* MessageRequestReadReceipts.swift in Sources */, 34BEDB1321C43F6A007B0EAE /* ImageEditorView.swift in Sources */, - 346B4A79236A138C00B56007 /* OWS116UpdatePrekeys.swift in Sources */, 34AC09EE211B39B100997B47 /* EditContactShareNameViewController.swift in Sources */, - 346129F71FD5F31400532771 /* OWS105AttachmentFilePaths.m in Sources */, 450998681FD8C0FF00D89EB3 /* AttachmentSharing.m in Sources */, - 346129F81FD5F31400532771 /* OWS100RemoveTSRecipientsMigration.m in Sources */, 34AC09DF211B39B100997B47 /* OWSNavigationController.m in Sources */, 34074F61203D0CBE004596AE /* OWSSounds.m in Sources */, 34C2EEB02270B8E200BCA1D0 /* StickerKeyboard.swift in Sources */, @@ -4933,14 +4787,12 @@ 34BEDB1721C80BCA007B0EAE /* OWSAnyTouchGestureRecognizer.m in Sources */, 340872C92239563500CB25B0 /* AttachmentItemCollection.swift in Sources */, 34080EFE2225F96D0087E99F /* ImageEditorPaletteView.swift in Sources */, - 34B6A909218B8824007C4606 /* OWS112TypingIndicatorsMigration.swift in Sources */, 4C6E446922AEDDEE007982E6 /* NewAccountDiscovery.swift in Sources */, 4C3E245D21F2B395000AE092 /* DirectionalPanGestureRecognizer.swift in Sources */, 3426A375256321190036407F /* OWSMessageTextView.m in Sources */, 8835DE08230E092F00DC6B66 /* FindByPhoneNumberViewController.swift in Sources */, 346129B51FD1F7E800532771 /* OWSProfileManager.m in Sources */, 8851DB4124CCE9E5001EACD2 /* Mention.swift in Sources */, - 4CBBCA6321714B4500EEB37D /* OWS110SortIdMigration.swift in Sources */, 342950832124C9750000B063 /* OWSTextView.m in Sources */, 34BBC85D220D19D600857249 /* ImageEditorPanGestureRecognizer.swift in Sources */, 348C686D246B0B110039705A /* ThreadUtil.swift in Sources */, @@ -4967,7 +4819,6 @@ 4C858A52212DC5E1001B45D3 /* UIImage+OWS.swift in Sources */, 34480B671FD0AA9400BC14EF /* UIFont+OWS.m in Sources */, 4C0387532339B3220062D293 /* UIColor+OWS.swift in Sources */, - 346129E61FD5C0C600532771 /* OWSDatabaseMigrationRunner.m in Sources */, 88D5887824846A7F00DC9AB6 /* InputAccessoryViewPlaceholder.swift in Sources */, 88D23D0B23CEBF4400B0E74B /* UserNotificationsAdaptee.swift in Sources */, 886BB3D825BA871B00079781 /* Wallpaper+SolidColor.swift in Sources */, @@ -4979,14 +4830,11 @@ 34AC09E2211B39B100997B47 /* ReturnToCallViewController.swift in Sources */, 345DE96023ED9AA500A8E6E3 /* GroupsV2ProfileKeyUpdater.swift in Sources */, 885091C02525650100428A37 /* PHPhotoLibrary+Xcode11.swift in Sources */, - 34080E4022E9F50200B4D9DA /* YDBToGRDBMigration.swift in Sources */, 34123C60239AA93B00782788 /* ViewOnceTooltip.swift in Sources */, 34AC0A12211B39EA00997B47 /* ContactTableViewCell.m in Sources */, 451F8A461FD715BA005CB9DA /* OWSGroupAvatarBuilder.m in Sources */, 34C2EEB42270D1CE00BCA1D0 /* StickerView.swift in Sources */, - 346129961FD1E30000532771 /* OWSDatabaseMigration.m in Sources */, 341CBFC42405B7C000F15C13 /* GroupsV2Impl+RestoreGroups.swift in Sources */, - 346129FB1FD5F31400532771 /* OWS101ExistingUsersBlockOnIdentityChange.m in Sources */, 34AC09EA211B39B100997B47 /* ModalActivityIndicatorViewController.swift in Sources */, 88BAE55F24875A24001F00F9 /* ImageEditorBlurRegionsItem.swift in Sources */, 344F248D2007CCD600CFB4F4 /* DisplayableText.swift in Sources */, @@ -4995,12 +4843,10 @@ 34AC0A1F211B39EA00997B47 /* AvatarImageView.swift in Sources */, 3466087220E550F400AFFE73 /* ConversationStyle.swift in Sources */, 3478506B1FD9B78A007B8332 /* NoopCallMessageHandler.swift in Sources */, - 4C9B4F23225025F100DD5B9A /* OWS1XXGRDBMigration.swift in Sources */, 340872CA2239563500CB25B0 /* AttachmentApprovalViewController.swift in Sources */, 346129AD1FD1F34E00532771 /* ImageCache.swift in Sources */, 3465948424352FE900E5C510 /* OWSTableViewController.swift in Sources */, 88EFF4F525AD1ACB000FAFBA /* ConversationItem.swift in Sources */, - 34D5872F208E2C4200D2255A /* OWS109OutgoingMessageState.m in Sources */, 340B870E23DF3E3A00BE0AFC /* GroupV2UpdatesImpl.swift in Sources */, 340872D02239787F00CB25B0 /* AttachmentTextToolbar.swift in Sources */, 3470249C238367EA0078D72C /* TextApprovalViewController.swift in Sources */, @@ -5009,14 +4855,11 @@ 34AC09F8211B39B100997B47 /* CountryCodeViewController.m in Sources */, 451F8A341FD710C3005CB9DA /* FullTextSearcher.swift in Sources */, 34080F04222858DC0087E99F /* OWSViewController+ImageEditor.swift in Sources */, - 346129FE1FD5F31400532771 /* OWS106EnsureProfileComplete.swift in Sources */, 34AC0A10211B39EA00997B47 /* TappableView.swift in Sources */, 3426A372256320420036407F /* CVText.swift in Sources */, - 346129F91FD5F31400532771 /* OWS104CreateRecipientIdentities.m in Sources */, 34C2EEAC2270A69400BCA1D0 /* CircleView.swift in Sources */, 34AC09E9211B39B100997B47 /* OWSTableViewController.m in Sources */, 340872CE2239596100CB25B0 /* AttachmentApprovalToolbar.swift in Sources */, - 346129F51FD5F31400532771 /* OWS102MoveLoggingPreferenceToUserDefaults.m in Sources */, 45194F8F1FD71FF500333B2C /* ThreadUtil.m in Sources */, 340B06C723C8DA2600929588 /* StorageService+GroupsV2.swift in Sources */, 34BEDB0E21C405B0007B0EAE /* ImageEditorModel.swift in Sources */, @@ -5028,7 +4871,6 @@ 45BC829D1FD9C4B400011CF3 /* ShareViewDelegate.swift in Sources */, 3461295B1FD1D74C00532771 /* Environment.m in Sources */, 3426A378256321C50036407F /* CVUtils.swift in Sources */, - 4CBF6F7B230B03C000549FFC /* OWS115CleanupProfileAvatars.swift in Sources */, 346129D51FD20ADC00532771 /* UIViewController+OWS.m in Sources */, 34BB3C5D23C6644B001651FC /* GroupsV2Utils.swift in Sources */, 8860CC212508507F00A4D18E /* GroupLinkPreview.swift in Sources */, @@ -5049,14 +4891,11 @@ 34080F02222853E30087E99F /* ImageEditorBrushViewController.swift in Sources */, 34AC0A14211B39EA00997B47 /* ContactCellView.m in Sources */, 34AC0A15211B39EA00997B47 /* ContactsViewHelper.m in Sources */, - 346129FF1FD5F31400532771 /* OWS103EnableVideoCalling.m in Sources */, 346129E31FD5C0BE00532771 /* VersionMigrations.m in Sources */, - 4C7537892193779700DF5E37 /* OWS113MultiAttachmentMediaMessages.swift in Sources */, 340872CB2239563500CB25B0 /* AttachmentPrepViewController.swift in Sources */, 88E34F2922F26CC100966CC2 /* StorageServiceProto+Sync.swift in Sources */, 3476236224081F8900D4FB6F /* GroupManager+SignalMessaging.swift in Sources */, 34AC0A16211B39EA00997B47 /* OWSNavigationBar.swift in Sources */, - 34BEDB0B21C2FA3D007B0EAE /* OWS114RemoveDynamicInteractions.swift in Sources */, 34AC0A1A211B39EA00997B47 /* CommonStrings.swift in Sources */, 34AC0A19211B39EA00997B47 /* OWSActionSheets.swift in Sources */, 340872DA22397FEB00CB25B0 /* AttachmentTextView.swift in Sources */, @@ -5066,7 +4905,6 @@ 34BBC859220C7ADA00857249 /* ImageEditorStrokeItem.swift in Sources */, 451F8A351FD710DE005CB9DA /* Searcher.swift in Sources */, 451F8A481FD715BA005CB9DA /* OWSContactAvatarBuilder.m in Sources */, - 4503F1C3204711D300CEE724 /* OWS107LegacySounds.m in Sources */, 3464450D22B7F93600A957B1 /* OWSOrphanDataCleaner.m in Sources */, 34FB6A5725D4127A00E599B1 /* OWSTableViewController2.swift in Sources */, 34AC0A18211B39EA00997B47 /* TappableStackView.swift in Sources */, @@ -5077,7 +4915,6 @@ 8809CE8122F534B200D38867 /* CustomKeyboard.swift in Sources */, 4541B71D209D3B7A0008608F /* ContactShareViewModel.swift in Sources */, 4C618199219DF03A009BD6B5 /* OWSButton.swift in Sources */, - 4598198F204E2F28009414F2 /* OWS108CallLoggingPreference.m in Sources */, 4C3E245C21F29FCE000AE092 /* Toast.swift in Sources */, 3456A73223D63EBE00947219 /* GroupsV2Protos.swift in Sources */, 34BBC84B220B2CB200857249 /* ImageEditorTextViewController.swift in Sources */, @@ -5102,7 +4939,6 @@ 88F67A0C24E5126D00435A71 /* HapticFeedback.swift in Sources */, 347191F923F457BD003A3106 /* GroupsV2AvatarDownloadOperation.swift in Sources */, 34641E182088D7E900E2EDE5 /* OWSScreenLock.swift in Sources */, - 349EA07C2162AEA800F7B17F /* OWS111UDAttributesMigration.swift in Sources */, 34BB3C5E23C6644B001651FC /* GroupsV2OutgoingChangesImpl.swift in Sources */, 8821334E2304E72700353626 /* NonContactTableViewCell.swift in Sources */, 34480B561FD0A7A400BC14EF /* DebugLogger.m in Sources */, @@ -5110,7 +4946,6 @@ 459B775C207BA46C0071D0AB /* OWSQuotedReplyModel.m in Sources */, 340872D622397E6800CB25B0 /* AttachmentCaptionToolbar.swift in Sources */, 3464451122B7F97100A957B1 /* DateUtil.m in Sources */, - 34ABB2C42090C59700C727A6 /* OWSResaveCollectionDBMigration.m in Sources */, 4C38E501230374D700E464B9 /* UIViewController+Permissions.m in Sources */, 4C948FF72146EB4800349F0D /* BlockListCache.swift in Sources */, 34BBC84F220B8A0100857249 /* ImageEditorCropViewController.swift in Sources */, @@ -5262,10 +5097,10 @@ 347342F72548587900D440CD /* ConversationViewController+BottomBar.swift in Sources */, 45B27B862037FFB400A539DF /* DebugUIFileBrowser.swift in Sources */, 3498AC892513896400B1F315 /* Dependencies+MainApp.swift in Sources */, - 340CCB6A23032762005243B3 /* YDBLegacyMigration.m in Sources */, 347C3834252CE69400F3D941 /* CVItemModel.swift in Sources */, 88A4CC09246CB0960082211F /* OnboardingTransferChoiceViewController.swift in Sources */, 3496955D219B605E00DCFE74 /* PhotoCollectionPickerController.swift in Sources */, + 34955A73260A366600F3789A /* OnboardingDroppedYdbViewController.swift in Sources */, 880D9027247F90CC003D2B14 /* Emoji+Available.swift in Sources */, 8835DDFD230CEE8900DC6B66 /* RecipientPickerDelegate.swift in Sources */, 3465947E2434CCC100E5C510 /* NewGroupConfirmViewController.swift in Sources */, @@ -5554,15 +5389,12 @@ 349BC861253A2651003C949A /* GroupsV2MigrationTest.swift in Sources */, 3421981C21061D2E00C57195 /* ByteParserTest.swift in Sources */, 34843B26214327C9004DED45 /* OWSOrphanDataCleanerTest.m in Sources */, - 340CCB722305962B005243B3 /* YDBToGRDBMigrationModelTest.swift in Sources */, 34BBC862220E883300857249 /* ImageEditorTest.swift in Sources */, - 34DB0BED2011548B007B313F /* OWSDatabaseConverterTest.m in Sources */, 3499998122EF1E2100654932 /* SearcherTest.swift in Sources */, 345AE2B62317048300DB6225 /* GRDBFinderTest.swift in Sources */, 34843B2C214FE296004DED45 /* MockEnvironment.m in Sources */, 45360B911F952AA900FA666C /* MarqueeLabel.swift in Sources */, 454EBAB41F2BE14C00ACE0BB /* OWSAnalytics.swift in Sources */, - 340CCB712305962B005243B3 /* YDBToGRDBMigrationKeyValueTest.swift in Sources */, 954AEE6A1DF33E01002E5410 /* ContactsPickerTest.swift in Sources */, 45666F581D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m in Sources */, B660F6E01C29868000687D6E /* UtilTest.m in Sources */, diff --git a/Signal/Images.xcassets/logo_blue.imageset/Contents.json b/Signal/Images.xcassets/logo_blue.imageset/Contents.json new file mode 100644 index 0000000000..ac9047b7ac --- /dev/null +++ b/Signal/Images.xcassets/logo_blue.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "logo_blue.pdf", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Signal/Images.xcassets/logo_blue.imageset/logo_blue.pdf b/Signal/Images.xcassets/logo_blue.imageset/logo_blue.pdf new file mode 100644 index 0000000000..63f77d03ab --- /dev/null +++ b/Signal/Images.xcassets/logo_blue.imageset/logo_blue.pdf @@ -0,0 +1,267 @@ +%PDF-1.7 + +1 0 obj + << /BBox [ 0.000000 0.000000 106.000000 106.000000 ] + /Resources << >> + /Subtype /Form + /Length 2 0 R + /Group << /Type /Group + /S /Transparency + >> + /Type /XObject + >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000031 -0.405746 cm +0.227451 0.462745 0.941176 scn +40.279968 104.857155 m +41.472469 100.037468 l +36.781410 98.883797 32.291866 97.027115 28.156218 94.530434 c +25.605595 98.786995 l +30.163071 101.538589 35.110466 103.585114 40.279968 104.857155 c +40.279968 104.857155 l +h +65.719971 104.857155 m +64.527466 100.037468 l +69.218529 98.883797 73.708069 97.027115 77.843719 94.530434 c +80.410904 98.786995 l +75.848297 101.540123 70.895203 103.586693 65.719971 104.857155 c +65.719971 104.857155 l +h +7.618719 80.800117 m +4.867129 76.242645 2.820604 71.295242 1.548563 66.125748 c +6.368250 64.933243 l +7.521918 69.624298 9.378601 74.113846 11.875282 78.249496 c +7.618719 80.800117 l +h +4.968719 53.405743 m +4.967119 55.814663 5.147055 58.220276 5.507000 60.602150 c +0.596219 61.347462 l +-0.198740 56.082825 -0.198740 50.728668 0.596219 45.464027 c +5.507000 46.209335 l +5.147055 48.591209 4.967119 50.996826 4.968719 53.405743 c +4.968719 53.405743 l +h +80.394348 8.024490 m +77.843719 12.281052 l +73.713211 9.785904 69.229362 7.929268 64.544029 6.774025 c +65.736526 1.954338 l +70.900299 3.227951 75.842003 5.274429 80.394348 8.024490 c +80.394348 8.024490 l +h +101.031219 53.405743 m +101.032822 50.996826 100.852882 48.591209 100.492935 46.209335 c +105.403717 45.464027 l +106.198677 50.728668 106.198677 56.082825 105.403717 61.347462 c +100.492935 60.602150 l +100.852882 58.220276 101.032822 55.814663 101.031219 53.405743 c +101.031219 53.405743 l +h +104.451370 40.685745 m +99.631683 41.878242 l +98.478020 37.187187 96.621338 32.697639 94.124657 28.561989 c +98.381218 25.994804 l +101.134346 30.557419 103.180908 35.510506 104.451370 40.685745 c +104.451370 40.685745 l +h +60.196377 5.904488 m +55.425617 5.186729 50.574322 5.186729 45.803562 5.904488 c +45.058250 0.993706 l +50.322887 0.198746 55.677044 0.198746 60.941685 0.993706 c +60.196377 5.904488 l +h +91.665123 24.909958 m +88.800392 21.030121 85.369637 17.602158 81.487473 14.740585 c +84.435593 10.740746 l +88.718185 13.889534 92.503540 17.663719 95.664963 21.936989 c +91.665123 24.909958 l +h +81.487473 92.070900 m +85.370239 89.206802 88.801033 85.776016 91.665123 81.893242 c +95.664963 84.874496 l +92.513618 89.145340 88.739563 92.919395 84.468719 96.070747 c +81.487473 92.070900 l +h +14.334813 81.893242 m +17.198910 85.776016 20.629698 89.206802 24.512470 92.070900 c +21.531219 96.070747 l +17.260380 92.919395 13.486319 89.145340 10.334969 84.874496 c +14.334813 81.893242 l +h +98.381218 80.800117 m +94.124657 78.249496 l +96.619804 74.118988 98.476440 69.635132 99.631683 64.949806 c +104.451370 66.142303 l +103.177757 71.306076 101.131279 76.247780 98.381218 80.800117 c +98.381218 80.800117 l +h +45.803562 100.898712 m +50.574322 101.616478 55.425617 101.616478 60.196377 100.898712 c +60.941685 105.809494 l +55.677044 106.604454 50.322887 106.604454 45.058250 105.809494 c +45.803562 100.898712 l +h +16.885439 9.424019 m +6.624969 7.030739 l +9.018250 17.291206 l +4.182001 18.425743 l +1.788719 8.165276 l +1.595951 7.342094 1.616416 6.483345 1.848178 5.670288 c +2.079939 4.857224 2.515332 4.116745 3.113153 3.518921 c +3.710974 2.921104 4.451451 2.485710 5.264512 2.253944 c +6.077572 2.022186 6.936323 2.001724 7.759501 2.194496 c +18.011688 4.546364 l +16.885439 9.424019 l +h +5.217157 22.856209 m +10.053407 21.729958 l +11.709657 28.843552 l +9.295546 32.900970 7.495555 37.293510 6.368250 41.878242 c +1.548563 40.685745 l +2.629022 36.294586 4.271208 32.061081 6.434500 28.089958 c +5.217157 22.856209 l +h +28.404655 12.090584 m +21.291063 10.434334 l +22.417313 5.598083 l +27.651062 6.815430 l +31.622185 4.652138 35.855686 3.009949 40.246841 1.929489 c +41.439342 6.749184 l +36.864239 7.889954 32.482990 9.701057 28.437780 12.123711 c +28.404655 12.090584 l +h +52.999969 96.468246 m +45.305874 96.464264 37.753365 94.398903 31.127958 90.486984 c +24.502552 86.575066 19.046249 80.959473 15.326546 74.224274 c +11.606842 67.489075 9.759604 59.880276 9.976958 52.189251 c +10.194313 44.498226 12.468323 37.005898 16.562469 30.491524 c +12.421844 12.827614 l +30.085751 16.968239 l +35.735271 13.409973 42.134800 11.214119 48.778805 10.554146 c +55.422806 9.894173 62.129265 10.788162 68.368385 13.165497 c +74.607506 15.542824 80.208374 19.338371 84.728523 24.252289 c +89.248680 29.166206 92.564285 35.063873 94.413429 41.479401 c +96.262573 47.894932 96.594589 54.652561 95.383255 61.218460 c +94.171921 67.784363 91.450417 73.978653 87.433739 79.311996 c +83.417061 84.645355 78.215240 88.971649 72.239220 91.949142 c +66.263191 94.926636 59.676666 96.473740 52.999969 96.468246 c +52.999969 96.468246 l +h +f +n +Q + +endstream +endobj + +2 0 obj + 4584 +endobj + +3 0 obj + << /BBox [ 0.000000 0.000000 106.000000 106.000000 ] + /Resources << >> + /Subtype /Form + /Length 4 0 R + /Group << /Type /Group + /S /Transparency + >> + /Type /XObject + >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm +0.000000 0.000000 0.000000 scn +0.000000 106.000000 m +106.000000 106.000000 l +106.000000 0.000000 l +0.000000 0.000000 l +0.000000 106.000000 l +h +f +n +Q + +endstream +endobj + +4 0 obj + 237 +endobj + +5 0 obj + << /XObject << /X1 1 0 R >> + /ExtGState << /E1 << /SMask << /Type /Mask + /G 3 0 R + /S /Alpha + >> + /Type /ExtGState + >> >> + >> +endobj + +6 0 obj + << /Length 7 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +/E1 gs +/X1 Do +Q + +endstream +endobj + +7 0 obj + 46 +endobj + +8 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 106.000000 106.000000 ] + /Resources 5 0 R + /Contents 6 0 R + /Parent 9 0 R + >> +endobj + +9 0 obj + << /Kids [ 8 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +10 0 obj + << /Type /Catalog + /Pages 9 0 R + >> +endobj + +xref +0 11 +0000000000 65535 f +0000000010 00000 n +0000004844 00000 n +0000004867 00000 n +0000005354 00000 n +0000005376 00000 n +0000005674 00000 n +0000005776 00000 n +0000005797 00000 n +0000005972 00000 n +0000006046 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 10 0 R + /Size 11 +>> +startxref +6106 +%%EOF \ No newline at end of file diff --git a/Signal/Settings.bundle/Acknowledgements.plist b/Signal/Settings.bundle/Acknowledgements.plist index 1062640422..2a46a5b6f8 100644 --- a/Signal/Settings.bundle/Acknowledgements.plist +++ b/Signal/Settings.bundle/Acknowledgements.plist @@ -1763,26 +1763,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI Type PSGroupSpecifier - - FooterText - Software License Agreement (BSD License) - -Copyright (c) 2013, yap.TV Inc. All rights reserved. - -Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Neither the name of yap.TV nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of yap.TV Inc. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - License - MIT - Title - YapDatabase - Type - PSGroupSpecifier - FooterText This software is provided under: diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 9a01bd7e7f..5fb11f68b7 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -12,7 +12,6 @@ #import "Signal-Swift.h" #import "SignalApp.h" #import "ViewControllerUtils.h" -#import "YDBLegacyMigration.h" #import #import #import @@ -174,22 +173,20 @@ void uncaughtExceptionHandler(NSException *exception) deviceTransferRestoreFailed = ![DeviceTransferService.shared launchCleanup]; }]; - // XXX - careful when moving this. It must happen before we load YDB and/or GRDB. + // XXX - careful when moving this. It must happen before we load GRDB. [self verifyDBKeysAvailableBeforeBackgroundLaunch]; // We need to do this _after_ we set up logging, when the keychain is unlocked, - // but before we access YapDatabase, files on disk, or NSUserDefaults + // but before we access the database, files on disk, or NSUserDefaults. NSError *_Nullable launchError = nil; LaunchFailure launchFailure = LaunchFailure_None; - BOOL isYdbNotReady = ![YDBLegacyMigration ensureIsYDBReadyForAppExtensions:&launchError]; if (deviceTransferRestoreFailed) { launchFailure = LaunchFailure_CouldNotRestoreTransferredData; - } else if (isYdbNotReady || launchError != nil) { + } else if (launchError != nil) { launchFailure = LaunchFailure_CouldNotLoadDatabase; } else if (StorageCoordinator.hasInvalidDatabaseVersion) { // Prevent: - // * Users who have used GRDB revert to using YDB. // * Users with an unknown GRDB schema revert to using an earlier GRDB schema. launchFailure = LaunchFailure_UnknownDatabaseVersion; } @@ -287,20 +284,7 @@ void uncaughtExceptionHandler(NSException *exception) return; } - // someone currently using yap - if (StorageCoordinator.hasYdbFile && !SSKPreferences.isYdbMigrated - && OWSPrimaryStorage.isDatabasePasswordAccessible) { - return; - } - - // someone who migrated from yap to grdb needs the GRDB spec - if (SSKPreferences.isYdbMigrated && GRDBDatabaseStorageAdapter.isKeyAccessible) { - return; - } - - // someone who never used yap needs the GRDB spec - if (!StorageCoordinator.hasYdbFile && StorageCoordinator.hasGrdbFile - && GRDBDatabaseStorageAdapter.isKeyAccessible) { + if (StorageCoordinator.hasGrdbFile && GRDBDatabaseStorageAdapter.isKeyAccessible) { return; } diff --git a/Signal/src/Models/ThreadMapping.swift b/Signal/src/Models/ThreadMapping.swift index bb1e2d49c3..797a670c06 100644 --- a/Signal/src/Models/ThreadMapping.swift +++ b/Signal/src/Models/ThreadMapping.swift @@ -635,54 +635,6 @@ class ThreadMapping: NSObject { return ThreadMappingDiff(sectionChanges: [], rowChanges: rowChanges) } - - // For performance reasons, the database modification notifications are used - // to determine which items were modified. If YapDatabase ever changes the - // structure or semantics of these notifications, we'll need to update this - // code to reflect that. - @objc - public func updatedYapItemIds(forNotifications notifications: [NSNotification]) -> Set { - // We'll move this into the Yap adapter when addressing updates/observation - let viewName: String = TSThreadDatabaseViewExtensionName - - var updatedItemIds = Set() - for notification in notifications { - // Unpack the YDB notification, looking for row changes. - guard let userInfo = - notification.userInfo else { - owsFailDebug("Missing userInfo.") - continue - } - guard let viewChangesets = - userInfo[YapDatabaseExtensionsKey] as? NSDictionary else { - // No changes for any views, skip. - continue - } - guard let changeset = - viewChangesets[viewName] as? NSDictionary else { - // No changes for this view, skip. - continue - } - // This constant matches a private constant in YDB. - let changeset_key_changes: String = "changes" - guard let changesetChanges = changeset[changeset_key_changes] as? [Any] else { - owsFailDebug("Missing changeset changes.") - continue - } - for change in changesetChanges { - if change as? YapDatabaseViewSectionChange != nil { - // Ignore. - } else if let rowChange = change as? YapDatabaseViewRowChange { - updatedItemIds.insert(rowChange.collectionKey.key) - } else { - owsFailDebug("Invalid change: \(type(of: change)).") - continue - } - } - } - - return updatedItemIds - } } extension Collection where Element: Equatable { diff --git a/Signal/src/Signal-Bridging-Header.h b/Signal/src/Signal-Bridging-Header.h index b266d41362..820a08bb56 100644 --- a/Signal/src/Signal-Bridging-Header.h +++ b/Signal/src/Signal-Bridging-Header.h @@ -28,7 +28,6 @@ #import "OWSBezierPathView.h" #import "OWSBubbleShapeView.h" #import "OWSBubbleView.h" -#import "OWSDatabaseMigration.h" #import "OWSDeviceTableViewCell.h" #import "OWSLinkDeviceViewController.h" #import "OWSMessageTextView.h" diff --git a/Signal/src/ViewControllers/AppSettings/Internal/InternalSettingsViewController.swift b/Signal/src/ViewControllers/AppSettings/Internal/InternalSettingsViewController.swift index b7010c4082..a3d7035f46 100644 --- a/Signal/src/ViewControllers/AppSettings/Internal/InternalSettingsViewController.swift +++ b/Signal/src/ViewControllers/AppSettings/Internal/InternalSettingsViewController.swift @@ -113,9 +113,7 @@ class InternalSettingsViewController: OWSTableViewController2 { infoSection.add(.label(withText: "dataStoreForUI: \(NSStringForDataStore(StorageCoordinator.dataStoreForUI))")) - infoSection.add(.label(withText: "hasYdbFile: \(StorageCoordinator.hasYdbFile)")) infoSection.add(.label(withText: "hasGrdbFile: \(StorageCoordinator.hasGrdbFile)")) - infoSection.add(.label(withText: "hasUnmigratedYdbFile: \(StorageCoordinator.hasUnmigratedYdbFile)")) infoSection.add(.label(withText: "didEverUseYdb: \(SSKPreferences.didEverUseYdb())")) infoSection.add(.actionItem( diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 02e5b49e95..4ed1f097ea 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -3010,9 +3010,7 @@ typedef enum : NSUInteger { [self dismissViewControllerAnimated:YES completion:nil]; // We always want to scroll to the bottom of the conversation after the local user - // sends a message. Normally, this is taken care of in yapDatabaseModified:, but - // we don't listen to db modifications when this view isn't visible, i.e. when the - // attachment approval view is presented. + // sends a message. [self scrollToBottomOfConversationAnimated:NO]; } diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMisc.m b/Signal/src/ViewControllers/DebugUI/DebugUIMisc.m index f71c567cac..ff9d65bc9c 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMisc.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMisc.m @@ -23,14 +23,6 @@ NS_ASSUME_NONNULL_BEGIN -@interface OWSStorage (DebugUI) - -- (NSData *)databasePassword; - -@end - -#pragma mark - - @implementation DebugUIMisc #pragma mark - Factory Methods @@ -106,17 +98,6 @@ NS_ASSUME_NONNULL_BEGIN }]]; - if (thread) { - [items addObject:[OWSTableItem itemWithTitle:@"Send Encrypted Database" - actionBlock:^{ - [DebugUIMisc sendEncryptedDatabase:thread]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send Unencrypted Database" - actionBlock:^{ - [DebugUIMisc sendUnencryptedDatabase:thread]; - }]]; - } - [items addObject:[OWSTableItem itemWithTitle:@"Show 2FA Reminder" actionBlock:^() { UIViewController *reminderVC = @@ -154,21 +135,9 @@ NS_ASSUME_NONNULL_BEGIN actionBlock:^(UIViewController *viewController) { [DebugUIMisc sharePDFs:2]; }]]; - - [items addObject:[OWSTableItem - itemWithTitle:@"Increment Database Extension Versions" - actionBlock:^() { - if (StorageCoordinator.dataStoreForUI == DataStoreYdb) { - for (NSString *extensionName in OWSPrimaryStorage.shared.registeredExtensionNames) { - [OWSStorage incrementVersionOfDatabaseExtension:extensionName]; - } - } - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Fetch system contacts" actionBlock:^() { [Environment.shared.contactsManagerImpl requestSystemContactsOnce]; }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Cycle websockets" actionBlock:^() { [SSKEnvironment.shared.socketManager cycleSocket]; @@ -316,40 +285,6 @@ NS_ASSUME_NONNULL_BEGIN }); } -+ (void)sendEncryptedDatabase:(TSThread *)thread -{ - NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"sqlite"]; - NSString *fileName = filePath.lastPathComponent; - - __block BOOL success; - DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) { - NSError *error; - success = [[NSFileManager defaultManager] copyItemAtPath:OWSPrimaryStorage.databaseFilePath - toPath:filePath - error:&error]; - if (!success || error) { - OWSFailDebug(@"Could not copy database file: %@.", error); - success = NO; - } - }); - - if (!success) { - return; - } - - NSString *utiType = [MIMETypeUtil utiTypeForFileExtension:fileName.pathExtension]; - NSError *error; - _Nullable id dataSource = [DataSourcePath dataSourceWithFilePath:filePath - shouldDeleteOnDeallocation:YES - error:&error]; - OWSAssertDebug(dataSource != nil); - [dataSource setSourceFilename:fileName]; - SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType]; - NSData *databasePassword = [OWSPrimaryStorage.shared databasePassword]; - attachment.captionText = [databasePassword hexadecimalString]; - [self sendAttachment:attachment thread:thread]; -} - + (void)sendAttachment:(SignalAttachment *)attachment thread:(TSThread *)thread { if (!attachment || [attachment hasError]) { @@ -366,31 +301,6 @@ NS_ASSUME_NONNULL_BEGIN }]; } -+ (void)sendUnencryptedDatabase:(TSThread *)thread -{ - NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"sqlite"]; - NSString *fileName = filePath.lastPathComponent; - - NSError *error = [OWSPrimaryStorage.shared.newDatabaseConnection backupToPath:filePath]; - if (error != nil) { - OWSFailDebug(@"Could not copy database file: %@.", error); - return; - } - - NSString *utiType = [MIMETypeUtil utiTypeForFileExtension:fileName.pathExtension]; - _Nullable id dataSource = [DataSourcePath dataSourceWithFilePath:filePath - shouldDeleteOnDeallocation:YES - error:&error]; - if (dataSource == nil) { - OWSFailDebug(@"Could not create dataSource: %@.", error); - return; - } - - [dataSource setSourceFilename:fileName]; - SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType]; - [self sendAttachment:attachment thread:thread]; -} - + (void)shareAssets:(NSUInteger)count fromAssetLoaders:(NSArray *)assetLoaders { @@ -526,14 +436,6 @@ NS_ASSUME_NONNULL_BEGIN // KnownStickerPack [[[KnownStickerPack alloc] initWithInfo:stickerPackInfo] anyInsertWithTransaction:transaction]; - // OWSMessageDecryptJob - // - // TODO: Generate real envelope data. - if (StorageCoordinator.dataStoreForUI == DataStoreYdb) { - [[[OWSMessageDecryptJob alloc] initWithEnvelopeData:[Randomness generateRandomBytes:16] - serverDeliveryTimestamp:0] anyInsertWithTransaction:transaction]; - } - // OWSMessageContentJob // // TODO: Generate real envelope data. diff --git a/Signal/src/ViewControllers/HomeView/ConversationListViewController.m b/Signal/src/ViewControllers/HomeView/ConversationListViewController.m index b620faf0d8..4348eda192 100644 --- a/Signal/src/ViewControllers/HomeView/ConversationListViewController.m +++ b/Signal/src/ViewControllers/HomeView/ConversationListViewController.m @@ -37,12 +37,12 @@ typedef NS_ENUM(NSInteger, ConversationListMode) { ConversationListMode_Inbox, }; -// The bulk of the content in this view is driven by a YapDB view/mapping. +// The bulk of the content in this view is driven by ThreadMapping. // However, we also want to optionally include ReminderView's at the top // and an "Archived Conversations" button at the bottom. Rather than introduce // index-offsets into the Mapping calculation, we introduce two pseudo groups // to add a top and bottom section to the content, and create cells for those -// sections without consulting the YapMapping. +// sections without consulting the ThreadMapping. // This is a bit of a hack, but it consolidates the hacks into the Reminder/Archive section // and allows us to leaves the bulk of the content logic on the happy path. NSString *const kReminderViewPseudoGroup = @"kReminderViewPseudoGroup"; @@ -1920,16 +1920,6 @@ NSString *const kArchiveButtonPseudoGroup = @"kArchiveButtonPseudoGroup"; return (ConversationListViewController *)topViewController; } -- (NSString *)currentGrouping -{ - switch (self.conversationListMode) { - case ConversationListMode_Inbox: - return TSInboxGroup; - case ConversationListMode_Archive: - return TSArchiveGroup; - } -} - #pragma mark - Previewing #pragma mark Old Style diff --git a/Signal/src/ViewControllers/Registration/OnboardingController.swift b/Signal/src/ViewControllers/Registration/OnboardingController.swift index a957cdcd18..297335d6ce 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingController.swift @@ -228,7 +228,11 @@ public class OnboardingController: NSObject { Logger.info("milestone: \(milestone)") switch milestone { case .verifiedPhoneNumber, .verifiedLinkedDevice: - return OnboardingSplashViewController(onboardingController: self) + if SSKPreferences.didDropYdb() { + return OnboardingDroppedYdbViewController(onboardingController: self) + } else { + return OnboardingSplashViewController(onboardingController: self) + } case .setupProfile: return OnboardingProfileCreationViewController(onboardingController: self) case .restorePin: diff --git a/Signal/src/ViewControllers/Registration/OnboardingDroppedYdbViewController.swift b/Signal/src/ViewControllers/Registration/OnboardingDroppedYdbViewController.swift new file mode 100644 index 0000000000..28e6c9ce91 --- /dev/null +++ b/Signal/src/ViewControllers/Registration/OnboardingDroppedYdbViewController.swift @@ -0,0 +1,81 @@ +// +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. +// + +import UIKit +import PromiseKit + +@objc +public class OnboardingDroppedYdbViewController: OnboardingBaseViewController { + + override public func loadView() { + view = UIView() + view.addSubview(primaryView) + primaryView.autoPinEdgesToSuperviewEdges() + + view.backgroundColor = Theme.backgroundColor + + let heroImageView = UIImageView.withTemplateImageName("logo_blue", + tintColor: .ows_accentBlue) + heroImageView.autoSetDimensions(to: .square(100)) + heroImageView.setContentHuggingHigh() + + let titleLabel = self.createTitleLabel(text: NSLocalizedString("ONBOARDING_DROPPED_YDB_TITLE", + comment: "Title of the 'onboarding after dropped YDB' view.")) + primaryView.addSubview(titleLabel) + titleLabel.accessibilityIdentifier = "onboarding.droppedYdb." + "titleLabel" + + let explanationLabel = UILabel() + explanationLabel.text = NSLocalizedString("ONBOARDING_DROPPED_YDB_EXPLANATION", + comment: "Explanation on the 'onboarding after dropped YDB' view.") + explanationLabel.textColor = Theme.secondaryTextAndIconColor + explanationLabel.font = UIFont.ows_dynamicTypeSubheadlineClamped + explanationLabel.numberOfLines = 0 + explanationLabel.textAlignment = .center + explanationLabel.lineBreakMode = .byWordWrapping + explanationLabel.accessibilityIdentifier = "onboarding.droppedYdb." + "explanationLabel" + + let nextButton = self.primaryButton(title: CommonStrings.nextButton, + selector: #selector(nextPressed)) + nextButton.accessibilityIdentifier = "onboarding.droppedYdb." + "nextButton" + let primaryButtonView = OnboardingBaseViewController.horizontallyWrap(primaryButton: nextButton) + + let topStack = UIStackView(arrangedSubviews: [ + heroImageView, + UIView.spacer(withHeight: 28), + titleLabel, + UIView.spacer(withHeight: 12), + explanationLabel + ]) + topStack.axis = .vertical + topStack.alignment = .center + + let topVSpacer = UIView.vStretchingSpacer() + let bottomVSpacer = UIView.vStretchingSpacer() + + let stackView = UIStackView(arrangedSubviews: [ + topVSpacer, + topStack, + bottomVSpacer, + primaryButtonView + ]) + stackView.axis = .vertical + stackView.alignment = .fill + + primaryView.addSubview(stackView) + stackView.autoPinEdgesToSuperviewMargins() + + topVSpacer.autoMatch(.height, to: .height, of: bottomVSpacer) + } + + // MARK: - Events + + @objc func nextPressed() { + Logger.info("") + + SSKPreferences.setDidDropYdb(false) + + let splash = OnboardingSplashViewController(onboardingController: onboardingController) + navigationController?.setViewControllers([splash], animated: true) + } +} diff --git a/Signal/src/environment/AppEnvironment.swift b/Signal/src/environment/AppEnvironment.swift index 36e43dc1c3..7da40f5d03 100644 --- a/Signal/src/environment/AppEnvironment.swift +++ b/Signal/src/environment/AppEnvironment.swift @@ -69,8 +69,6 @@ public class AppEnvironment: NSObject { super.init() SwiftSingletons.register(self) - - YDBToGRDBMigration.add(keyStore: AppUpdateNag.shared.keyValueStore, label: "AppUpdateNag") } @objc diff --git a/Signal/src/util/AppUpdateNag.swift b/Signal/src/util/AppUpdateNag.swift index e76c096a90..c5d70d961b 100644 --- a/Signal/src/util/AppUpdateNag.swift +++ b/Signal/src/util/AppUpdateNag.swift @@ -115,7 +115,9 @@ class AppUpdateNag: NSObject { } switch frontmostViewController { - case is ConversationSplitViewController, is OnboardingSplashViewController: + case is ConversationSplitViewController, + is OnboardingSplashViewController, + is OnboardingDroppedYdbViewController: self.setLastNagDate(Date()) self.clearFirstHeardOfNewVersionDate() presentUpgradeNag(appStoreRecord: appStoreRecord) diff --git a/Signal/src/util/Device Transfer/DeviceTransferService+Restore.swift b/Signal/src/util/Device Transfer/DeviceTransferService+Restore.swift index a7e1d0dfeb..bfc5b24e23 100644 --- a/Signal/src/util/Device Transfer/DeviceTransferService+Restore.swift +++ b/Signal/src/util/Device Transfer/DeviceTransferService+Restore.swift @@ -53,7 +53,7 @@ extension DeviceTransferService { return false } - guard database.key.count == kSQLCipherKeySpecLength else { + guard database.key.count == GRDBDatabaseStorageAdapter.kSQLCipherKeySpecLength else { owsFailDebug("incorrect database key length") return false } diff --git a/Signal/src/util/MainAppContext.m b/Signal/src/util/MainAppContext.m index 8e8fc07ded..d1fcb05cbe 100644 --- a/Signal/src/util/MainAppContext.m +++ b/Signal/src/util/MainAppContext.m @@ -18,9 +18,6 @@ NSString *const ReportedApplicationStateDidChangeNotification = @"ReportedApplic @property (nonatomic, nullable) NSMutableArray *appActiveBlocks; -// POST GRDB TODO: Remove this -@property (nonatomic) NSUUID *disposableDatabaseUUID; - @property (nonatomic, readonly) UIApplicationState mainApplicationStateOnLaunch; @end @@ -45,7 +42,6 @@ NSString *const ReportedApplicationStateDidChangeNotification = @"ReportedApplic self.reportedApplicationState = UIApplicationStateInactive; _appLaunchTime = [NSDate new]; - _disposableDatabaseUUID = [NSUUID UUID]; _mainApplicationStateOnLaunch = [UIApplication sharedApplication].applicationState; [[NSNotificationCenter defaultCenter] addObserver:self @@ -392,11 +388,7 @@ NSString *const ReportedApplicationStateDidChangeNotification = @"ReportedApplic - (NSString *)appDatabaseBaseDirectoryPath { - if (SDSDatabaseStorage.shouldUseDisposableGrdb) { - return [self.appSharedDataDirectoryPath stringByAppendingPathComponent:self.disposableDatabaseUUID.UUIDString]; - } else { - return self.appSharedDataDirectoryPath; - } + return self.appSharedDataDirectoryPath; } - (NSUserDefaults *)appUserDefaults diff --git a/Signal/src/util/YDBLegacyMigration.h b/Signal/src/util/YDBLegacyMigration.h deleted file mode 100644 index 8db40ac099..0000000000 --- a/Signal/src/util/YDBLegacyMigration.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -@interface YDBLegacyMigration : NSObject - -+ (BOOL)ensureIsYDBReadyForAppExtensions:(NSError **)error; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Signal/src/util/YDBLegacyMigration.m b/Signal/src/util/YDBLegacyMigration.m deleted file mode 100644 index 862c5a3f92..0000000000 --- a/Signal/src/util/YDBLegacyMigration.m +++ /dev/null @@ -1,129 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import "YDBLegacyMigration.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation YDBLegacyMigration - -+ (void)appDidBecomeReady -{ - if (CurrentAppContext().isMainApp) { - // Disable the SAE until the main app has: - // - // * Successfully completed launch process at least once in the post-SAE world. - // * Successfully completed launch process at least once in the post-GRDB world. - [OWSPreferences setIsYdbReadyForAppExtensions]; - - if (StorageCoordinator.dataStoreForUI == DataStoreGrdb) { - [OWSPreferences setIsGrdbReadyForAppExtensions]; - } - } -} - -+ (BOOL)ensureIsYDBReadyForAppExtensions:(NSError **)errorHandle -{ - OWSAssertDebug(errorHandle != nil); - - AppReadinessRunNowOrWhenAppDidBecomeReadySync(^{ [self appDidBecomeReady]; }); - - if ([OWSPreferences isReadyForAppExtensions]) { - return YES; - } - - OWSBackgroundTask *_Nullable backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; - SUPPRESS_DEADSTORE_WARNING(backgroundTask); - - NSError *_Nullable error = [self convertDatabaseIfNecessary]; - - if (!error) { - [NSUserDefaults migrateToSharedUserDefaults]; - } - - if (!error) { - error = [OWSPrimaryStorage migrateToSharedData]; - } - if (!error) { - error = [OWSUserProfile migrateToSharedData]; - } - if (!error) { - error = [TSAttachmentStream migrateToSharedData]; - } - - if (error) { - OWSFailDebug(@"database conversion failed: %@", error); - *errorHandle = error; - return NO; - } - - OWSAssertDebug(backgroundTask); - backgroundTask = nil; - - return YES; -} - -+ (nullable NSError *)convertDatabaseIfNecessary -{ - OWSLogInfo(@""); - - NSString *databaseFilePath = [OWSPrimaryStorage legacyDatabaseFilePath]; - if (![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]) { - OWSLogVerbose(@"no legacy database file found"); - return nil; - } - - NSError *_Nullable error; - NSData *_Nullable databasePassword = [OWSStorage tryToLoadDatabaseLegacyPassphrase:&error]; - if (!databasePassword || error) { - return (error - ?: OWSErrorWithCodeDescription( - OWSErrorCodeDatabaseConversionFatalError, @"Failed to load database password")); - } - - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSLogVerbose(@"saltData: %@", saltData.hexadecimalString); - - // Derive and store the raw cipher key spec, to avoid the ongoing tax of future KDF - NSData *_Nullable keySpecData = - [YapDatabaseCryptoUtils deriveDatabaseKeySpecForPassword:databasePassword saltData:saltData]; - - if (!keySpecData) { - OWSLogError(@"Failed to derive key spec."); - return NO; - } - - [OWSStorage storeDatabaseCipherKeySpec:keySpecData]; - - return YES; - }; - - YapDatabaseOptions *dbOptions = [OWSStorage defaultDatabaseOptions]; - error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:dbOptions - recordSaltBlock:recordSaltBlock]; - if (!error) { - [OWSStorage removeLegacyPassphrase]; - } - - return error; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Signal/test/PerformanceTests/MessageProcessingPerformanceTest.swift b/Signal/test/PerformanceTests/MessageProcessingPerformanceTest.swift index c06ab399f0..012cac21cd 100644 --- a/Signal/test/PerformanceTests/MessageProcessingPerformanceTest.swift +++ b/Signal/test/PerformanceTests/MessageProcessingPerformanceTest.swift @@ -27,7 +27,6 @@ class MessageProcessingPerformanceTest: PerformanceBaseTest { override func setUp() { super.setUp() - storageCoordinator.useGRDBForTests() try! databaseStorage.grdbStorage.setupUIDatabase() let dbObserver = BlockObserver(block: { [weak self] in self?.dbObserverBlock?() }) diff --git a/Signal/test/PerformanceTests/MessageSendingPerformanceTest.swift b/Signal/test/PerformanceTests/MessageSendingPerformanceTest.swift index f071c151b4..aaefdde867 100644 --- a/Signal/test/PerformanceTests/MessageSendingPerformanceTest.swift +++ b/Signal/test/PerformanceTests/MessageSendingPerformanceTest.swift @@ -53,7 +53,6 @@ class MessageSendingPerformanceTest: PerformanceBaseTest { func testGRDBPerf_messageSending_contactThread() { // This is an example of a performance test case. - storageCoordinator.useGRDBForTests() try! databaseStorage.grdbStorage.setupUIDatabase() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { sendMessages_contactThread() @@ -63,7 +62,6 @@ class MessageSendingPerformanceTest: PerformanceBaseTest { func testGRDBPerf_messageSending_groupThread() { // This is an example of a performance test case. - storageCoordinator.useGRDBForTests() try! databaseStorage.grdbStorage.setupUIDatabase() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { sendMessages_groupThread() diff --git a/Signal/test/PerformanceTests/SDSPerformanceTest.swift b/Signal/test/PerformanceTests/SDSPerformanceTest.swift index 3c29e2c28e..63c53f0c65 100644 --- a/Signal/test/PerformanceTests/SDSPerformanceTest.swift +++ b/Signal/test/PerformanceTests/SDSPerformanceTest.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // import Foundation @@ -11,14 +11,12 @@ class SDSPerformanceTest: PerformanceBaseTest { // MARK: - Insert Messages func testYDBPerf_insertMessages() { - storageCoordinator.useYDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { insertMessages() } } func testGRDBPerf_insertMessages() { - storageCoordinator.useGRDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { insertMessages() } @@ -62,14 +60,12 @@ class SDSPerformanceTest: PerformanceBaseTest { // MARK: - Fetch Messages func testYDBPerf_fetchMessages() { - storageCoordinator.useYDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { fetchMessages() } } func testGRDBPerf_fetchMessages() { - storageCoordinator.useGRDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { fetchMessages() } @@ -108,28 +104,24 @@ class SDSPerformanceTest: PerformanceBaseTest { // MARK: - Enumerate Messages func testYDBPerf_enumerateMessagesUnbatched() { - storageCoordinator.useYDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { enumerateMessages(batched: false) } } func testGRDBPerf_enumerateMessagesUnbatched() { - storageCoordinator.useGRDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { enumerateMessages(batched: false) } } func testYDBPerf_enumerateMessagesBatched() { - storageCoordinator.useYDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { enumerateMessages(batched: true) } } func testGRDBPerf_enumerateMessagesBatched() { - storageCoordinator.useGRDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { enumerateMessages(batched: true) } diff --git a/Signal/test/PerformanceTests/ThreadFinderPerformanceTest.swift b/Signal/test/PerformanceTests/ThreadFinderPerformanceTest.swift index d37cb934d6..8963ecbb8d 100644 --- a/Signal/test/PerformanceTests/ThreadFinderPerformanceTest.swift +++ b/Signal/test/PerformanceTests/ThreadFinderPerformanceTest.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // import Foundation @@ -9,14 +9,12 @@ import SignalServiceKit class ThreadFinderPerformanceTest: PerformanceBaseTest { func testGRDBPerf_enumerateVisibleThreads() { - storageCoordinator.useGRDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { enumerateVisibleThreads(isArchived: false) } } func testGRDBPerf_enumerateVisibleThreads_isArchived() { - storageCoordinator.useGRDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { enumerateVisibleThreads(isArchived: true) } diff --git a/Signal/test/PerformanceTests/ThreadPerformanceTest.swift b/Signal/test/PerformanceTests/ThreadPerformanceTest.swift index fc58395b14..c83c36839e 100644 --- a/Signal/test/PerformanceTests/ThreadPerformanceTest.swift +++ b/Signal/test/PerformanceTests/ThreadPerformanceTest.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // import Foundation @@ -14,14 +14,12 @@ class ThreadPerformanceTest: PerformanceBaseTest { // MARK: - writeThreadAndInteractions func testYDBPerf_writeThreadAndInteractions() { - storageCoordinator.useYDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { writeThreadAndInteractions() } } func testGRDBPerf_writeThreadAndInteractions() { - storageCoordinator.useGRDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { writeThreadAndInteractions() } @@ -50,14 +48,12 @@ class ThreadPerformanceTest: PerformanceBaseTest { // MARK: - writeAndDeleteThreadAndInteractions func testYDBPerf_writeAndDeleteThreadAndInteractions() { - storageCoordinator.useYDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { writeAndDeleteThreadAndInteractions() } } func testGRDBPerf_writeAndDeleteThreadAndInteractions() { - storageCoordinator.useGRDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { writeAndDeleteThreadAndInteractions() } @@ -83,14 +79,12 @@ class ThreadPerformanceTest: PerformanceBaseTest { // MARK: - writeAndUpdateAndDeleteThreadAndInteractions func testYDBPerf_writeAndUpdateAndDeleteThreadAndInteractions() { - storageCoordinator.useYDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { writeAndUpdateAndDeleteThreadAndInteractions() } } func testGRDBPerf_writeAndUpdateAndDeleteThreadAndInteractions() { - storageCoordinator.useGRDBForTests() measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { writeAndUpdateAndDeleteThreadAndInteractions() } diff --git a/Signal/test/SignalBaseTest.h b/Signal/test/SignalBaseTest.h index 8374f608a8..344bc28350 100644 --- a/Signal/test/SignalBaseTest.h +++ b/Signal/test/SignalBaseTest.h @@ -1,11 +1,10 @@ // -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // #import "MockEnvironment.h" #import #import -#import NS_ASSUME_NONNULL_BEGIN @@ -14,14 +13,9 @@ NS_ASSUME_NONNULL_BEGIN @interface SignalBaseTest : XCTestCase -@property (nonatomic, readonly, nullable) OWSPrimaryStorage *primaryStorage; - - (void)readWithBlock:(void (^)(SDSAnyReadTransaction *transaction))block; - (void)writeWithBlock:(void (^)(SDSAnyWriteTransaction *transaction))block; -- (void)yapReadWithBlock:(void (^)(YapDatabaseReadTransaction *transaction))block; -- (void)yapWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block; - @end NS_ASSUME_NONNULL_END diff --git a/Signal/test/SignalBaseTest.m b/Signal/test/SignalBaseTest.m index c2a2a5d5de..e1e8aa5494 100644 --- a/Signal/test/SignalBaseTest.m +++ b/Signal/test/SignalBaseTest.m @@ -5,22 +5,12 @@ #import "SignalBaseTest.h" #import "Environment.h" #import -#import #import #import #import -#import NS_ASSUME_NONNULL_BEGIN -@interface SignalBaseTest () - -@property (nonatomic) YapDatabaseConnection *ydbConnection; - -@end - -#pragma mark - - @implementation SignalBaseTest - (void)setUp @@ -38,8 +28,6 @@ NS_ASSUME_NONNULL_BEGIN [MockEnvironment activate]; ((MockSSKEnvironment *)SSKEnvironment.shared).groupsV2Ref = [GroupsV2Impl new]; - - self.ydbConnection = [SSKEnvironment.shared.primaryStorage newDatabaseConnection]; } - (void)tearDown @@ -59,22 +47,6 @@ NS_ASSUME_NONNULL_BEGIN DatabaseStorageWrite(SDSDatabaseStorage.shared, block); } -- (void)yapReadWithBlock:(void (^)(YapDatabaseReadTransaction *transaction))block -{ - OWSAssert(block); - OWSAssert(self.ydbConnection); - - [self.ydbConnection readWithBlock:block]; -} - -- (void)yapWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block -{ - OWSAssert(block); - OWSAssert(self.ydbConnection); - - [self.ydbConnection readWriteWithBlock:block]; -} - @end NS_ASSUME_NONNULL_END diff --git a/Signal/test/util/GRDBFinderTest.swift b/Signal/test/util/GRDBFinderTest.swift index 1ca92b942f..dc26e6f750 100644 --- a/Signal/test/util/GRDBFinderTest.swift +++ b/Signal/test/util/GRDBFinderTest.swift @@ -12,8 +12,6 @@ class GRDBFinderTest: SignalBaseTest { override func setUp() { super.setUp() - storageCoordinator.useGRDBForTests() - // ensure local client has necessary "registered" state let localE164Identifier = "+13235551234" let localUUID = UUID() diff --git a/Signal/test/util/OWSDatabaseConverterTest.m b/Signal/test/util/OWSDatabaseConverterTest.m deleted file mode 100644 index 33c8dd9d31..0000000000 --- a/Signal/test/util/OWSDatabaseConverterTest.m +++ /dev/null @@ -1,1180 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "SignalBaseTest.h" -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface YapDatabase (OWSDatabaseConverterTest) - -- (void)flushInternalQueue; -- (void)flushCheckpointQueue; - -@end - -@interface OWSStorage (OWSDatabaseConverterTest) - -+ (YapDatabaseDeserializer)logOnFailureDeserializer; -+ (void)storeKeyChainValue:(NSData *)data keychainKey:(NSString *)keychainKey; -+ (nullable NSData *)tryToLoadKeyChainValue:(NSString *)keychainKey errorHandle:(NSError **)errorHandle; - -@end - -#pragma mark - - -@interface YapDatabaseCryptoUtils (OWSDatabaseConverterTest) - -+ (NSData *)readFirstNBytesOfDatabaseFile:(NSString *)filePath byteCount:(NSUInteger)byteCount; - -@end - -#pragma mark - - -@interface OWSDatabaseConverterTest : SignalBaseTest - -@end - -#pragma mark - - -@implementation OWSDatabaseConverterTest - -- (NSData *)randomDatabasePassword -{ - return [Randomness generateRandomBytes:30]; -} - -- (NSData *)randomDatabaseSalt -{ - return [Randomness generateRandomBytes:(int)kSQLCipherSaltLength]; -} - -- (NSData *)randomDatabaseKeySpec -{ - return [Randomness generateRandomBytes:(int)kSQLCipherKeySpecLength]; -} - -// * Open a YapDatabase. -// * Do some work with a block. -// * Close the database. -// * Verify that the database is closed. -- (void)openYapDatabase:(NSString *)databaseFilePath - databasePassword:(NSData *_Nullable)databasePassword - databaseSalt:(NSData *_Nullable)databaseSalt - databaseKeySpec:(NSData *_Nullable)databaseKeySpec - databaseBlock:(void (^_Nonnull)(YapDatabase *))databaseBlock -{ - OWSAssertDebug(databaseFilePath.length > 0); - OWSAssertDebug(databasePassword.length > 0 || databaseKeySpec.length > 0); - OWSAssertDebug(databaseBlock); - - OWSLogVerbose(@"openYapDatabase: %@", databaseFilePath); - [DDLog flushLog]; - - __weak YapDatabase *_Nullable weakDatabase = nil; - dispatch_queue_t snapshotQueue; - dispatch_queue_t writeQueue; - - @autoreleasepool { - YapDatabaseOptions *options = [[YapDatabaseOptions alloc] init]; - options.corruptAction = YapDatabaseCorruptAction_Fail; - if (databasePassword) { - OWSLogInfo(@"Using password."); - options.cipherKeyBlock = ^{ - return databasePassword; - }; - } - options.enableMultiProcessSupport = YES; - - if (databaseSalt) { - OWSLogInfo(@"Using salt & unencrypted header."); - options.cipherSaltBlock = ^{ - return databaseSalt; - }; - options.cipherUnencryptedHeaderLength = kSqliteHeaderLength; - } else if (databaseKeySpec) { - OWSLogInfo(@"Using key spec & unencrypted header."); - options.cipherKeySpecBlock = ^{ - return databaseKeySpec; - }; - options.cipherUnencryptedHeaderLength = kSqliteHeaderLength; - } - options.legacyCipherCompatibilityVersion = 3; - - OWSAssertDebug(options.cipherDefaultkdfIterNumber == 0); - OWSAssertDebug(options.kdfIterNumber == 0); - OWSAssertDebug(options.cipherPageSize == 0); - OWSAssertDebug(options.pragmaPageSize == 0); - OWSAssertDebug(options.pragmaJournalSizeLimit == 0); - - YapDatabase *database = [[YapDatabase alloc] initWithPath:databaseFilePath - serializer:nil - deserializer:[OWSStorage logOnFailureDeserializer] - options:options]; - OWSAssertDebug(database); - - weakDatabase = database; - snapshotQueue = database->snapshotQueue; - writeQueue = database->writeQueue; - - databaseBlock(database); - - [database flushInternalQueue]; - [database flushCheckpointQueue]; - - // Close the database. - database = nil; - } - - // Flush the database's queues, which may contain lingering - // references to the database. - dispatch_sync(snapshotQueue, - ^{ - }); - dispatch_sync(writeQueue, - ^{ - }); - - // Wait for notifications from writes to be fired. - { - XCTestExpectation *expectation = [self expectationWithDescription:@"Database modified notifications"]; - - dispatch_async(dispatch_get_main_queue(), ^{ - // Database modified notifications are fired on the main queue. - // Once this block executes, the main queue has been flushed - // and we know that all database modified notifications are - // complete. - [expectation fulfill]; - }); - - // YapDatabase can retain cached references to the registration - // connections for up to 5 seconds. This can block deallocation - // of the YapDatabase instance. Since we're trying to block on - // closing of the database (so that we can examine its contents - // on disk), we wait for the worst case duration. - [self waitForExpectationsWithTimeout:5.0 - handler:^(NSError *error) { - if (error) { - OWSLogInfo(@"Timeout Error: %@", error); - } - }]; - } - - // Verify that the database is indeed closed. - YapDatabase *_Nullable strongDatabase = weakDatabase; - OWSAssertDebug(!strongDatabase); -} - -- (SDSKeyValueStore *)keyValueStore -{ - return [[SDSKeyValueStore alloc] initWithCollection:@"test_collection_name"]; -} - -- (void)createTestDatabase:(NSString *)databaseFilePath - databasePassword:(NSData *_Nullable)databasePassword - databaseSalt:(NSData *_Nullable)databaseSalt - databaseKeySpec:(NSData *_Nullable)databaseKeySpec -{ - OWSAssertDebug(databaseFilePath.length > 0); - OWSAssertDebug(databasePassword.length > 0 || databaseKeySpec.length > 0); - - OWSAssertDebug(![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - [self openYapDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec - databaseBlock:^(YapDatabase *database) { - [self logHeaderOfDatabaseFile:databaseFilePath - label:@"mid-creation"]; - - YapDatabaseConnection *dbConnection = database.newConnection; - [dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self.keyValueStore setBool:YES key:@"test_key_name" transaction:transaction.asAnyWrite]; - }]; - [dbConnection flushTransactionsWithCompletionQueue:dispatch_get_main_queue() completionBlock:nil]; - }]; - - OWSAssertDebug([[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - NSError *_Nullable error = nil; - NSDictionary *fileAttributes = - [[NSFileManager defaultManager] attributesOfItemAtPath:databaseFilePath error:&error]; - OWSAssertDebug(fileAttributes && !error); - OWSLogVerbose(@"test database file size: %@", fileAttributes[NSFileSize]); -} - -- (BOOL)verifyTestDatabase:(NSString *)databaseFilePath - databasePassword:(NSData *_Nullable)databasePassword - databaseSalt:(NSData *_Nullable)databaseSalt - databaseKeySpec:(NSData *_Nullable)databaseKeySpec -{ - OWSAssertDebug(databaseFilePath.length > 0); - OWSAssertDebug(databasePassword.length > 0 || databaseKeySpec.length > 0); - - OWSAssertDebug([[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - __block BOOL isValid = NO; - [self openYapDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec - databaseBlock:^(YapDatabase *database) { - YapDatabaseConnection *dbConnection = database.newConnection; - __block BOOL value; - [dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - value = - [self.keyValueStore getBool:@"test_key_name" defaultValue:NO transaction:transaction.asAnyRead]; - }]; - isValid = YES == value; - }]; - - OWSAssertDebug([[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - return isValid; -} - -- (nullable NSString *)createUnconvertedDatabase:(NSData *)databasePassword -{ - return [self createDatabase:databasePassword databaseSalt:nil databaseKeySpec:nil]; -} - -- (NSString *)createTempDatabaseFilePath -{ - NSString *databaseFilePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"sqlite"]; - - OWSLogInfo(@"databaseFilePath: %@", databaseFilePath); - [DDLog flushLog]; - - return databaseFilePath; -} - -// If databaseSalt and databaseKeySpec are both nil, creates a non-converted database. -// Otherwise creates a pre-converted database. -- (nullable NSString *)createDatabase:(NSData *_Nullable)databasePassword - databaseSalt:(NSData *_Nullable)databaseSalt - databaseKeySpec:(NSData *_Nullable)databaseKeySpec -{ - OWSAssertDebug(databasePassword.length > 0 || databaseKeySpec.length > 0); - - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - [self createTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec]; - - [self logHeaderOfDatabaseFile:databaseFilePath - label:@"created"]; - - BOOL isValid = [self verifyTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec]; - OWSAssertDebug(isValid); - - return databaseFilePath; -} - -#pragma mark - Tests - -- (void)testDoesDatabaseNeedToBeConverted_Unconverted -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSString *_Nullable databaseFilePath = [self createUnconvertedDatabase:databasePassword]; - XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); -} - -- (void)testDoesDatabaseNeedToBeConverted_ConvertedWithoutKeyspec -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSData *databaseSalt = [self randomDatabaseSalt]; - NSData *_Nullable databaseKeySpec = nil; - NSString *_Nullable databaseFilePath = - [self createDatabase:databasePassword databaseSalt:databaseSalt databaseKeySpec:databaseKeySpec]; - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); -} - -- (void)testDoesDatabaseNeedToBeConverted_ConvertedWithKeyspec -{ - NSData *_Nullable databasePassword = nil; - NSData *_Nullable databaseSalt = nil; - NSData *databaseKeySpec = [self randomDatabaseKeySpec]; - NSString *_Nullable databaseFilePath = - [self createDatabase:databasePassword databaseSalt:databaseSalt databaseKeySpec:databaseKeySpec]; - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); -} - -// Verifies that legacy users with non-converted databases can convert. -- (void)testDatabaseConversion_WithoutKeyspec -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSString *_Nullable databaseFilePath = [self createUnconvertedDatabase:databasePassword]; - XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - __block NSData *_Nullable databaseSalt = nil; - __block NSData *_Nullable databaseKeySpec = nil; - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSAssertDebug(!databaseSalt); - OWSAssertDebug(saltData); - - databaseSalt = saltData; - databaseKeySpec = [YapDatabaseCryptoUtils deriveDatabaseKeySpecForPassword:databasePassword saltData:saltData]; - XCTAssert(databaseKeySpec.length == kSQLCipherKeySpecLength); - - return YES; - }; - - NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:OWSStorage.defaultDatabaseOptions - recordSaltBlock:recordSaltBlock]; - if (error) { - OWSLogError(@"error: %@", error); - } - XCTAssertNil(error); - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - XCTAssertNotNil(databaseSalt); - XCTAssertEqual(databaseSalt.length, kSQLCipherSaltLength); - XCTAssertNotNil(databaseKeySpec); - XCTAssertEqual(databaseKeySpec.length, kSQLCipherKeySpecLength); - - BOOL isValid = [self verifyTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:nil]; - XCTAssertTrue(isValid); -} - -// Verifies that legacy users with non-converted databases can convert. -- (void)testDatabaseConversion_WithKeyspec -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSString *_Nullable databaseFilePath = [self createUnconvertedDatabase:databasePassword]; - XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - __block NSData *_Nullable databaseSalt = nil; - - __block NSData *_Nullable databaseKeySpec = nil; - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSAssertDebug(!databaseSalt); - OWSAssertDebug(saltData); - - databaseSalt = saltData; - databaseKeySpec = [YapDatabaseCryptoUtils deriveDatabaseKeySpecForPassword:databasePassword saltData:saltData]; - XCTAssert(databaseKeySpec.length == kSQLCipherKeySpecLength); - - return YES; - }; - - NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:OWSStorage.defaultDatabaseOptions - recordSaltBlock:recordSaltBlock]; - if (error) { - OWSLogError(@"error: %@", error); - } - XCTAssertNil(error); - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - XCTAssertNotNil(databaseSalt); - XCTAssertEqual(databaseSalt.length, kSQLCipherSaltLength); - XCTAssertNotNil(databaseKeySpec); - XCTAssertEqual(databaseKeySpec.length, kSQLCipherKeySpecLength); - - BOOL isValid = [self verifyTestDatabase:databaseFilePath - databasePassword:nil - databaseSalt:nil - databaseKeySpec:databaseKeySpec]; - XCTAssertTrue(isValid); -} - -// If we fail to record the salt for some reason, we'll be unable to re-open the database -// halt the conversion in hopes that either the failure is intermittent or we can push out -// a patch to fix the problem without having lost the user's DB. -- (void)testDatabaseConversionDoesNotProceedWhenRecordingSaltFails -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSString *_Nullable databaseFilePath = [self createUnconvertedDatabase:databasePassword]; - XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - __block NSData *_Nullable databaseSalt = nil; - - __block NSData *_Nullable databaseKeySpec = nil; - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSAssertDebug(!databaseSalt); - OWSAssertDebug(saltData); - - // Simulate a failure to record the new salt, e.g. if KDF returns nil - return NO; - }; - - NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:OWSStorage.defaultDatabaseOptions - recordSaltBlock:recordSaltBlock]; - - XCTAssertNotNil(error); - XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - BOOL isValid = [self verifyTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:nil - databaseKeySpec:databaseKeySpec]; - XCTAssertTrue(isValid); -} - -// Verifies that legacy users with non-converted databases can convert. -- (void)testDatabaseConversionPerformance_WithKeyspec -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - const int kItemCount = 50 * 1000; - - // Create and populate an unconverted database. - [self openYapDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:nil - databaseKeySpec:nil - databaseBlock:^(YapDatabase *database) { - YapDatabaseConnection *dbConnection = database.newConnection; - [dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - for (int i = 0; i < kItemCount; i++) { - NSString *key = [NSString stringWithFormat:@"key-%d", i]; - [transaction setObject:@"test-object" forKey:key inCollection:@"test_collection_name"]; - } - }]; - }]; - - XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - __block NSData *_Nullable databaseSalt = nil; - __block NSData *_Nullable databaseKeySpec = nil; - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSAssertDebug(!databaseSalt); - OWSAssertDebug(saltData); - - databaseSalt = saltData; - databaseKeySpec = [YapDatabaseCryptoUtils deriveDatabaseKeySpecForPassword:databasePassword saltData:saltData]; - XCTAssert(databaseKeySpec.length == kSQLCipherKeySpecLength); - - return YES; - }; - - NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:OWSStorage.defaultDatabaseOptions - recordSaltBlock:recordSaltBlock]; - if (error) { - OWSLogError(@"error: %@", error); - } - XCTAssertNil(error); - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - XCTAssertNotNil(databaseSalt); - XCTAssertEqual(databaseSalt.length, kSQLCipherSaltLength); - XCTAssertNotNil(databaseKeySpec); - XCTAssertEqual(databaseKeySpec.length, kSQLCipherKeySpecLength); - - // Verify the contents of the unconverted database. - __block BOOL isValid = NO; - [self openYapDatabase:databaseFilePath - databasePassword:nil - databaseSalt:nil - databaseKeySpec:databaseKeySpec - databaseBlock:^(YapDatabase *database) { - YapDatabaseConnection *dbConnection = database.newConnection; - __block NSUInteger keyCount; - [dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - keyCount = [self.keyValueStore numberOfKeysWithTransaction:transaction.asAnyRead]; - }]; - isValid = keyCount == kItemCount; - }]; - XCTAssertTrue(isValid); -} - -// Verifies new users who create new pre-converted databases. -- (void)testDatabaseCreation_WithoutKeySpec -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSData *databaseSalt = [self randomDatabaseSalt]; - NSData *_Nullable databaseKeySpec = nil; - NSString *_Nullable databaseFilePath = - [self createDatabase:databasePassword databaseSalt:databaseSalt databaseKeySpec:databaseKeySpec]; - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSAssertDebug(saltData); - - XCTFail(@"No conversion should be necessary"); - return NO; - }; - - NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:OWSStorage.defaultDatabaseOptions - recordSaltBlock:recordSaltBlock]; - if (error) { - OWSLogError(@"error: %@", error); - } - XCTAssertNil(error); - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - BOOL isValid = [self verifyTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec]; - XCTAssertTrue(isValid); -} - -// Verifies new users who create new pre-converted databases. -- (void)testDatabaseCreation_WithKeySpec -{ - NSData *_Nullable databasePassword = nil; - NSData *_Nullable databaseSalt = nil; - NSData *databaseKeySpec = [self randomDatabaseKeySpec]; - NSString *_Nullable databaseFilePath = - [self createDatabase:databasePassword databaseSalt:databaseSalt databaseKeySpec:databaseKeySpec]; - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSAssertDebug(saltData); - - XCTFail(@"No conversion should be necessary"); - return NO; - }; - - NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:OWSStorage.defaultDatabaseOptions - recordSaltBlock:recordSaltBlock]; - if (error) { - OWSLogError(@"error: %@", error); - } - XCTAssertNil(error); - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - BOOL isValid = [self verifyTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec]; - XCTAssertTrue(isValid); -} - -// Simulates a legacy user who needs to convert their database. -- (void)testConversionWithoutYapDatabase -{ - sqlite3 *db; - sqlite3_stmt *stmt; - const int ROWSTOINSERT = 3; - - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - OWSAssertDebug(![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - NSData *keyData = [self randomDatabasePassword]; - - /* Step 1. Create a new encrypted database. */ - - int openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_PRIVATECACHE; - - int rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS t1 (a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_prepare_v2(db, "INSERT INTO t1(b) VALUES (?);", -1, &stmt, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - for(int row = 0; row < ROWSTOINSERT; row++) { - rc = sqlite3_bind_text(stmt, 1, [[NSString stringWithFormat:@"%d", (int) arc4random()] UTF8String], -1, SQLITE_TRANSIENT); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_step(stmt); - XCTAssertTrue(rc == SQLITE_DONE); - rc = sqlite3_reset(stmt); - XCTAssertTrue(rc == SQLITE_OK); - } - rc = sqlite3_finalize(stmt); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - NSString *salt = [self executeSingleStringQuery:@"PRAGMA cipher_salt;" - db:db]; - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); - - [self logHeaderOfDatabaseFile:databaseFilePath - label:@"Unconverted header"]; - - /* Step 2. Rewrite header */ - - rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA synchronous = NORMAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA journal_size_limit = 1048576;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA cipher_plaintext_header_size = 32;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA user_version = 2;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - int log, ckpt; - rc = sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_FULL, &log, &ckpt); - XCTAssertTrue(rc == SQLITE_OK); - OWSLogInfo(@"log = %d, ckpt = %d", log, ckpt); - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); - - [self logHeaderOfDatabaseFile:databaseFilePath - label:@"Converted header"]; - - /* Step 3. Open the database and query it */ - - rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - NSString *saltPragma = [NSString stringWithFormat:@"PRAGMA cipher_salt = \"x'%@'\";", salt]; - OWSLogInfo(@"salt pragma = %@", saltPragma); - rc = sqlite3_exec(db, [saltPragma UTF8String], NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA cipher_plaintext_header_size = 32;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA synchronous = NORMAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA journal_size_limit = 1048576;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - XCTAssertEqual(2, [self executeSingleIntQuery:@"SELECT count(*) FROM sqlite_master;" db:db]); - - XCTAssertEqual(ROWSTOINSERT, [self executeSingleIntQuery:@"SELECT count(*) FROM t1;" db:db]); - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); -} - -- (int)executeSingleIntQuery:(NSString *)sql - db:(sqlite3 *)db -{ - sqlite3_stmt *stmt; - - int rc = sqlite3_prepare_v2(db, sql.UTF8String, -1, &stmt, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_step(stmt); - XCTAssertTrue(rc = SQLITE_ROW); - - int result = sqlite3_column_int(stmt, 0); - - rc = sqlite3_finalize(stmt); - XCTAssertTrue(rc == SQLITE_OK); - - return result; -} - -- (NSString *)executeSingleStringQuery:(NSString *)sql - db:(sqlite3 *)db -{ - sqlite3_stmt *stmt; - - int rc = sqlite3_prepare_v2(db, sql.UTF8String, -1, &stmt, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_step(stmt); - XCTAssertTrue(rc = SQLITE_ROW); - NSString *result = [NSString stringWithFormat:@"%s", sqlite3_column_text(stmt, 0)]; - - rc = sqlite3_finalize(stmt); - XCTAssertTrue(rc == SQLITE_OK); - - return result; -} - -// Simulates a new user who makes a new, pre-converted database. -- (void)testNewUserWithoutYapDatabase -{ - sqlite3 *db; - sqlite3_stmt *stmt; - const int ROWSTOINSERT = 3; - - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - OWSAssertDebug(![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - NSData *keyData = [self randomDatabasePassword]; - NSData *databaseSalt = [self randomDatabaseSalt]; - NSString *salt = databaseSalt.hexadecimalString; - - /* Step 1. Create a new encrypted database. */ - - int openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_PRIVATECACHE; - - int rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - NSString *saltPragma = [NSString stringWithFormat:@"PRAGMA cipher_salt = \"x'%@'\";", salt]; - OWSLogInfo(@"salt pragma = %@", saltPragma); - rc = sqlite3_exec(db, [saltPragma UTF8String], NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA cipher_plaintext_header_size = 32;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS t1 (a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_prepare_v2(db, "INSERT INTO t1(b) VALUES (?);", -1, &stmt, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - for(int row = 0; row < ROWSTOINSERT; row++) { - rc = sqlite3_bind_text(stmt, 1, [[NSString stringWithFormat:@"%d", (int) arc4random()] UTF8String], -1, SQLITE_TRANSIENT); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_step(stmt); - XCTAssertTrue(rc == SQLITE_DONE); - rc = sqlite3_reset(stmt); - XCTAssertTrue(rc == SQLITE_OK); - } - rc = sqlite3_finalize(stmt); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); - - /* Step 2. Open the database and query it */ - - rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - // NSString *saltPragma = [NSString stringWithFormat:@"PRAGMA cipher_salt = \"x'%@'\";", salt]; - // OWSLogInfo(@"salt pragma = %@", saltPragma); - rc = sqlite3_exec(db, [saltPragma UTF8String], NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA cipher_plaintext_header_size = 32;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA synchronous = NORMAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA journal_size_limit = 1048576;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - XCTAssertEqual(2, [self executeSingleIntQuery:@"SELECT count(*) FROM sqlite_master;" db:db]); - - XCTAssertEqual(ROWSTOINSERT, [self executeSingleIntQuery:@"SELECT count(*) FROM t1;" db:db]); - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); -} - -// Similar to testNewUserWithoutYapDatabase, but does more of the -// database configuration that YapDatabase does. -- (void)testNewUserLikeYapDatabase -{ - sqlite3 *db; - sqlite3_stmt *stmt; - const int ROWSTOINSERT = 3; - - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - OWSAssertDebug(![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - NSData *keyData = [self randomDatabasePassword]; - NSData *databaseSalt = [self randomDatabaseSalt]; - NSString *salt = databaseSalt.hexadecimalString; - - /* Step 1. Create a new encrypted database. */ - - int openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_PRIVATECACHE; - - int rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - NSString *saltPragma = [NSString stringWithFormat:@"PRAGMA cipher_salt = \"x'%@'\";", salt]; - OWSLogInfo(@"salt pragma = %@", saltPragma); - rc = sqlite3_exec(db, [saltPragma UTF8String], NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA cipher_plaintext_header_size = 32;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - { - int status = sqlite3_exec(db, "PRAGMA auto_vacuum = FULL; VACUUM;", NULL, NULL, NULL); - XCTAssertEqual(status, SQLITE_OK); - - // Set synchronous to normal for THIS sqlite instance. - // - // This does NOT affect normal connections. - // That is, this does NOT affect YapDatabaseConnection instances. - // The sqlite connections of normal YapDatabaseConnection instances will follow the set pragmaSynchronous value. - // - // The reason we hardcode normal for this sqlite instance is because - // it's only used to write the initial snapshot value. - // And this doesn't need to be durable, as it is initialized to zero everytime. - // - // (This sqlite db is also used to perform checkpoints. - // But a normal value won't affect these operations, - // as they will perform sync operations whether the connection is normal or full.) - - status = sqlite3_exec(db, "PRAGMA synchronous = NORMAL;", NULL, NULL, NULL); - XCTAssertEqual(status, SQLITE_OK); - - // Set journal_size_imit. - // - // We only need to do set this pragma for THIS connection, - // because it is the only connection that performs checkpoints. - - NSString *pragma_journal_size_limit = - [NSString stringWithFormat:@"PRAGMA journal_size_limit = %d;", 0]; - - status = sqlite3_exec(db, [pragma_journal_size_limit UTF8String], NULL, NULL, NULL); - XCTAssertEqual(status, SQLITE_OK); - - // Disable autocheckpointing. - // - // YapDatabase has its own optimized checkpointing algorithm built-in. - // It knows the state of every active connection for the database, - // so it can invoke the checkpoint methods at the precise time in which a checkpoint can be most effective. - - status = sqlite3_wal_autocheckpoint(db, 0); - XCTAssertEqual(status, SQLITE_OK); - } - - rc = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS t1 (a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_prepare_v2(db, "INSERT INTO t1(b) VALUES (?);", -1, &stmt, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - for(int row = 0; row < ROWSTOINSERT; row++) { - rc = sqlite3_bind_text(stmt, 1, [[NSString stringWithFormat:@"%d", (int) arc4random()] UTF8String], -1, SQLITE_TRANSIENT); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_step(stmt); - XCTAssertTrue(rc == SQLITE_DONE); - rc = sqlite3_reset(stmt); - XCTAssertTrue(rc == SQLITE_OK); - } - rc = sqlite3_finalize(stmt); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); - - /* Step 2. Open the database and query it */ - - rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, [saltPragma UTF8String], NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA cipher_plaintext_header_size = 32;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA synchronous = NORMAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA journal_size_limit = 1048576;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - XCTAssertEqual(2, [self executeSingleIntQuery:@"SELECT count(*) FROM sqlite_master;" db:db]); - - XCTAssertEqual(ROWSTOINSERT, [self executeSingleIntQuery:@"SELECT count(*) FROM t1;" db:db]); - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); -} - -- (void)logHeaderOfDatabaseFile:(NSString *)databaseFilePath - label:(NSString *)label -{ - OWSAssertDebug(databaseFilePath.length > 0); - OWSAssertDebug(label.length > 0); - - NSData *headerData = - [YapDatabaseCryptoUtils readFirstNBytesOfDatabaseFile:databaseFilePath byteCount:kSqliteHeaderLength]; - OWSAssertDebug(headerData); - NSMutableString *output = [NSMutableString new]; - [output appendFormat:@"Hex: %@, ", headerData.hexadecimalString]; - [output appendString:@"Ascii: "]; - NSMutableCharacterSet *characterSet = [NSMutableCharacterSet new]; - [characterSet formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]]; - [characterSet formUnionWithCharacterSet:[NSCharacterSet alphanumericCharacterSet]]; - [characterSet formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]]; - [characterSet formUnionWithCharacterSet:[NSCharacterSet symbolCharacterSet]]; - - const unsigned char *bytes = (const unsigned char *) headerData.bytes; - for (NSUInteger i=0; i < headerData.length; i++) { - unsigned char byte = bytes[i]; - if ([characterSet characterIsMember:(unichar)byte]) { - [output appendFormat:@"%C", (unichar)byte]; - } else { - [output appendString:@"_"]; - } - } - OWSLogInfo(@"%@: %@", label, output); -} - - -#pragma mark - keychain strategy benchmarks - - -- (void)verifyTestDatabase:(NSString *)databaseFilePath - databaseKeySpecBlock:(NSData *_Nullable (^_Nullable)(void))databaseKeySpecBlock - databasePasswordBlock:(NSData *_Nullable (^_Nullable)(void))databasePasswordBlock - databaseSaltBlock:(NSData *_Nullable (^_Nullable)(void))databaseSaltBlock -{ - NSData *_Nullable databaseKeySpec = databaseKeySpecBlock ? databaseKeySpecBlock() : nil; - NSData *_Nullable databasePassword = databasePasswordBlock ? databasePasswordBlock() : nil; - NSData *_Nullable databaseSalt = databaseSaltBlock ? databaseSaltBlock() : nil; - - [self verifyTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec]; -} - -- (void)createTestDatabase:(NSString *)databaseFilePath - databaseKeySpecBlock:(NSData *_Nullable (^_Nullable)(void))databaseKeySpecBlock - databasePasswordBlock:(NSData *_Nullable (^_Nullable)(void))databasePasswordBlock - databaseSaltBlock:(NSData *_Nullable (^_Nullable)(void))databaseSaltBlock -{ - NSData *_Nullable databaseKeySpec = databaseKeySpecBlock ? databaseKeySpecBlock() : nil; - NSData *_Nullable databasePassword = databasePasswordBlock ? databasePasswordBlock() : nil; - NSData *_Nullable databaseSalt = databaseSaltBlock ? databaseSaltBlock() : nil; - - [self createTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec]; -} - -- (void)storeTestPasswordInKeychain:(NSData *)password -{ - // legacy password length - OWSAssertDebug(password.length == 30); - [OWSStorage storeKeyChainValue:password keychainKey:@"_OWSTestingPassword"]; -} - -- (nullable NSData *)fetchTestPasswordFromKeychain -{ - NSError *error; - NSData *password = [OWSStorage tryToLoadKeyChainValue:@"_OWSTestingPassword" errorHandle:&error]; - OWSAssertDebug(password); - OWSAssertDebug(!error); - // legacy password length - OWSAssertDebug(password.length == 30); - - return password; -} - -- (void)storeTestSaltInKeychain:(NSData *)salt -{ - OWSAssertDebug(salt.length == kSQLCipherSaltLength); - [OWSStorage storeKeyChainValue:salt keychainKey:@"_OWSTestingSalt"]; -} - -- (nullable NSData *)fetchTestSaltFromKeychain -{ - NSError *error; - NSData *salt = [OWSStorage tryToLoadKeyChainValue:@"_OWSTestingSalt" errorHandle:&error]; - OWSAssertDebug(salt); - OWSAssertDebug(!error); - OWSAssertDebug(salt.length == kSQLCipherSaltLength); - return salt; -} - -- (void)storeTestKeySpecInKeychain:(NSData *)keySpec -{ - OWSAssertDebug(keySpec.length == kSQLCipherKeySpecLength); - [OWSStorage storeKeyChainValue:keySpec keychainKey:@"_OWSTestingKeySpec"]; -} - -- (nullable NSData *)fetchTestKeySpecFromKeychain -{ - NSError *error; - NSData *keySpec = [OWSStorage tryToLoadKeyChainValue:@"_OWSTestingKeySpec" errorHandle:&error]; - OWSAssertDebug(keySpec); - OWSAssertDebug(!error); - OWSAssertDebug(keySpec.length == kSQLCipherKeySpecLength); - - return keySpec; -} - -- (void)testWidePassphraseFetchingStrategy -{ - NSData *password = [self randomDatabasePassword]; - NSData *salt = [self randomDatabaseSalt]; - - [self measureBlock:^{ - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - [self createTestDatabase:databaseFilePath - databaseKeySpecBlock:nil - databasePasswordBlock:^() { - return password; - } - databaseSaltBlock:^() { - return salt; - }]; - - [self verifyTestDatabase:databaseFilePath - databaseKeySpecBlock:nil - databasePasswordBlock:^() { - return password; - } - databaseSaltBlock:^() { - return salt; - }]; - }]; -} - -- (void)testGranularPassphraseFetchingStrategy -{ - NSData *password = [self randomDatabasePassword]; - NSData *salt = [self randomDatabaseSalt]; - [self storeTestPasswordInKeychain:password]; - [self storeTestSaltInKeychain:salt]; - - [self measureBlock:^{ - - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - - [self createTestDatabase:databaseFilePath - databaseKeySpecBlock:nil - databasePasswordBlock:^() { - return [self fetchTestPasswordFromKeychain]; - } - databaseSaltBlock:^() { - return [self fetchTestSaltFromKeychain]; - }]; - - [self verifyTestDatabase:databaseFilePath - databaseKeySpecBlock:nil - databasePasswordBlock:^() { - return [self fetchTestPasswordFromKeychain]; - } - databaseSaltBlock:^() { - return [self fetchTestSaltFromKeychain]; - }]; - }]; -} - -- (void)testGranularKeySpecFetchingStrategy -{ - NSData *keySpec = [self randomDatabaseKeySpec]; - [self storeTestKeySpecInKeychain:keySpec]; - - [self measureBlock:^{ - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - [self createTestDatabase:databaseFilePath - databaseKeySpecBlock:^() { - return [self fetchTestKeySpecFromKeychain]; - } - databasePasswordBlock:nil - databaseSaltBlock:nil]; - - [self verifyTestDatabase:databaseFilePath - databaseKeySpecBlock:^() { - return [self fetchTestKeySpecFromKeychain]; - } - databasePasswordBlock:nil - databaseSaltBlock:nil]; - }]; -} - -- (void)testWideKeyFetchingStrategy -{ - NSData *keySpec = [self randomDatabaseKeySpec]; - - [self measureBlock:^{ - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - [self createTestDatabase:databaseFilePath - databaseKeySpecBlock:^() { - return keySpec; - } - databasePasswordBlock:nil - databaseSaltBlock:nil]; - - [self verifyTestDatabase:databaseFilePath - databaseKeySpecBlock:^() { - return keySpec; - } - databasePasswordBlock:nil - databaseSaltBlock:nil]; - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Signal/test/util/YDBToGRDBMigrationKeyValueTest.swift b/Signal/test/util/YDBToGRDBMigrationKeyValueTest.swift deleted file mode 100644 index 7ae36ac57d..0000000000 --- a/Signal/test/util/YDBToGRDBMigrationKeyValueTest.swift +++ /dev/null @@ -1,556 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -import XCTest -import SignalServiceKit -@testable import SignalMessaging - -class YDBToGRDBMigrationKeyValueTest: SignalBaseTest { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testKeyValueInt() { - storageCoordinator.useGRDBForTests() - - let store1 = SDSKeyValueStore(collection: "store1") - let store2 = SDSKeyValueStore(collection: "store2") - let store3 = SDSKeyValueStore(collection: "store3") - - let randomValue = { - return Int(arc4random()) - } - let value0 = randomValue() - let value1 = randomValue() - let value2 = randomValue() - let value3 = randomValue() - let value4 = randomValue() - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - } - - self.yapWrite { transaction in - store1.setInt(value0, key: "key0", transaction: transaction.asAnyWrite) - store2.setInt(value1, key: "key0", transaction: transaction.asAnyWrite) - store3.setInt(value2, key: "key0", transaction: transaction.asAnyWrite) - store1.setInt(value3, key: "key1", transaction: transaction.asAnyWrite) - store2.setInt(value4, key: "key1", transaction: transaction.asAnyWrite) - } - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBKeyValueStoreMigrator(label: "store1", keyStore: store1, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store2", keyStore: store2, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store3", keyStore: store3, ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.read { transaction in - XCTAssertEqual(2, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(2, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(1, store3.numberOfKeys(transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store3.hasValue(forKey: "key0", transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertFalse(store3.hasValue(forKey: "key1", transaction: transaction)) - - XCTAssertEqual(value0, store1.getInt("key0", transaction: transaction)) - XCTAssertEqual(value1, store2.getInt("key0", transaction: transaction)) - XCTAssertEqual(value2, store3.getInt("key0", transaction: transaction)) - XCTAssertEqual(value3, store1.getInt("key1", transaction: transaction)) - XCTAssertEqual(value4, store2.getInt("key1", transaction: transaction)) - XCTAssertNil(store3.getInt("key1", transaction: transaction)) - - // NSNumber variations - XCTAssertEqual(NSNumber(value: value0), store1.getNSNumber("key0", transaction: transaction)) - XCTAssertEqual(NSNumber(value: value1), store2.getNSNumber("key0", transaction: transaction)) - XCTAssertEqual(NSNumber(value: value2), store3.getNSNumber("key0", transaction: transaction)) - XCTAssertEqual(NSNumber(value: value3), store1.getNSNumber("key1", transaction: transaction)) - XCTAssertEqual(NSNumber(value: value4), store2.getNSNumber("key1", transaction: transaction)) - XCTAssertNil(store3.getNSNumber("key1", transaction: transaction)) - } - } - - func testKeyValueUInt() { - storageCoordinator.useGRDBForTests() - - let store1 = SDSKeyValueStore(collection: "store1") - let store2 = SDSKeyValueStore(collection: "store2") - let store3 = SDSKeyValueStore(collection: "store3") - - let randomValue = { - return UInt(arc4random()) - } - let value0 = randomValue() - let value1 = randomValue() - let value2 = randomValue() - let value3 = randomValue() - let value4 = randomValue() - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - } - - self.yapWrite { transaction in - store1.setUInt(value0, key: "key0", transaction: transaction.asAnyWrite) - store2.setUInt(value1, key: "key0", transaction: transaction.asAnyWrite) - store3.setUInt(value2, key: "key0", transaction: transaction.asAnyWrite) - store1.setUInt(value3, key: "key1", transaction: transaction.asAnyWrite) - store2.setUInt(value4, key: "key1", transaction: transaction.asAnyWrite) - } - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBKeyValueStoreMigrator(label: "store1", keyStore: store1, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store2", keyStore: store2, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store3", keyStore: store3, ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.read { transaction in - XCTAssertEqual(2, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(2, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(1, store3.numberOfKeys(transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store3.hasValue(forKey: "key0", transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertFalse(store3.hasValue(forKey: "key1", transaction: transaction)) - - XCTAssertEqual(value0, store1.getUInt("key0", transaction: transaction)) - XCTAssertEqual(value1, store2.getUInt("key0", transaction: transaction)) - XCTAssertEqual(value2, store3.getUInt("key0", transaction: transaction)) - XCTAssertEqual(value3, store1.getUInt("key1", transaction: transaction)) - XCTAssertEqual(value4, store2.getUInt("key1", transaction: transaction)) - XCTAssertNil(store3.getUInt("key1", transaction: transaction)) - - // NSNumber variations - XCTAssertEqual(NSNumber(value: value0), store1.getNSNumber("key0", transaction: transaction)) - XCTAssertEqual(NSNumber(value: value1), store2.getNSNumber("key0", transaction: transaction)) - XCTAssertEqual(NSNumber(value: value2), store3.getNSNumber("key0", transaction: transaction)) - XCTAssertEqual(NSNumber(value: value3), store1.getNSNumber("key1", transaction: transaction)) - XCTAssertEqual(NSNumber(value: value4), store2.getNSNumber("key1", transaction: transaction)) - XCTAssertNil(store3.getNSNumber("key1", transaction: transaction)) - } - } - - func testKeyValueDouble() { - storageCoordinator.useGRDBForTests() - - let store1 = SDSKeyValueStore(collection: "store1") - let store2 = SDSKeyValueStore(collection: "store2") - let store3 = SDSKeyValueStore(collection: "store3") - - let randomValue = { - return Double(arc4random()) / Double(arc4random()) - } - let value0 = randomValue() - let value1 = randomValue() - let value2 = randomValue() - let value3 = randomValue() - let value4 = randomValue() - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - } - - self.yapWrite { transaction in - store1.setDouble(value0, key: "key0", transaction: transaction.asAnyWrite) - store2.setDouble(value1, key: "key0", transaction: transaction.asAnyWrite) - store3.setDouble(value2, key: "key0", transaction: transaction.asAnyWrite) - store1.setDouble(value3, key: "key1", transaction: transaction.asAnyWrite) - store2.setDouble(value4, key: "key1", transaction: transaction.asAnyWrite) - } - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBKeyValueStoreMigrator(label: "store1", keyStore: store1, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store2", keyStore: store2, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store3", keyStore: store3, ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.read { transaction in - XCTAssertEqual(2, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(2, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(1, store3.numberOfKeys(transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store3.hasValue(forKey: "key0", transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertFalse(store3.hasValue(forKey: "key1", transaction: transaction)) - - XCTAssertEqual(value0, store1.getDouble("key0", transaction: transaction)) - XCTAssertEqual(value1, store2.getDouble("key0", transaction: transaction)) - XCTAssertEqual(value2, store3.getDouble("key0", transaction: transaction)) - XCTAssertEqual(value3, store1.getDouble("key1", transaction: transaction)) - XCTAssertEqual(value4, store2.getDouble("key1", transaction: transaction)) - XCTAssertNil(store3.getDouble("key1", transaction: transaction)) - - // NSNumber variations - XCTAssertEqual(NSNumber(value: value0), store1.getNSNumber("key0", transaction: transaction)) - XCTAssertEqual(NSNumber(value: value1), store2.getNSNumber("key0", transaction: transaction)) - XCTAssertEqual(NSNumber(value: value2), store3.getNSNumber("key0", transaction: transaction)) - XCTAssertEqual(NSNumber(value: value3), store1.getNSNumber("key1", transaction: transaction)) - XCTAssertEqual(NSNumber(value: value4), store2.getNSNumber("key1", transaction: transaction)) - XCTAssertNil(store3.getNSNumber("key1", transaction: transaction)) - } - } - - func testKeyValueData() { - storageCoordinator.useGRDBForTests() - - let store1 = SDSKeyValueStore(collection: "store1") - let store2 = SDSKeyValueStore(collection: "store2") - let store3 = SDSKeyValueStore(collection: "store3") - - let randomValue = { - return UUID().uuidString.data(using: .utf8)! - } - let value0 = randomValue() - let value1 = randomValue() - let value2 = randomValue() - let value3 = randomValue() - let value4 = randomValue() - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - } - - self.yapWrite { transaction in - store1.setData(value0, key: "key0", transaction: transaction.asAnyWrite) - store2.setData(value1, key: "key0", transaction: transaction.asAnyWrite) - store3.setData(value2, key: "key0", transaction: transaction.asAnyWrite) - store1.setData(value3, key: "key1", transaction: transaction.asAnyWrite) - store2.setData(value4, key: "key1", transaction: transaction.asAnyWrite) - } - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBKeyValueStoreMigrator(label: "store1", keyStore: store1, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store2", keyStore: store2, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store3", keyStore: store3, ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.read { transaction in - XCTAssertEqual(2, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(2, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(1, store3.numberOfKeys(transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store3.hasValue(forKey: "key0", transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertFalse(store3.hasValue(forKey: "key1", transaction: transaction)) - - XCTAssertEqual(value0, store1.getData("key0", transaction: transaction)) - XCTAssertEqual(value1, store2.getData("key0", transaction: transaction)) - XCTAssertEqual(value2, store3.getData("key0", transaction: transaction)) - XCTAssertEqual(value3, store1.getData("key1", transaction: transaction)) - XCTAssertEqual(value4, store2.getData("key1", transaction: transaction)) - XCTAssertNil(store3.getData("key1", transaction: transaction)) - } - } - - func testKeyValueString() { - storageCoordinator.useGRDBForTests() - - let store1 = SDSKeyValueStore(collection: "store1") - let store2 = SDSKeyValueStore(collection: "store2") - let store3 = SDSKeyValueStore(collection: "store3") - - let randomValue = { - return UUID().uuidString - } - let value0 = randomValue() - let value1 = randomValue() - let value2 = randomValue() - let value3 = randomValue() - let value4 = randomValue() - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - } - - self.yapWrite { transaction in - store1.setString(value0, key: "key0", transaction: transaction.asAnyWrite) - store2.setString(value1, key: "key0", transaction: transaction.asAnyWrite) - store3.setString(value2, key: "key0", transaction: transaction.asAnyWrite) - store1.setString(value3, key: "key1", transaction: transaction.asAnyWrite) - store2.setString(value4, key: "key1", transaction: transaction.asAnyWrite) - } - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBKeyValueStoreMigrator(label: "store1", keyStore: store1, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store2", keyStore: store2, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store3", keyStore: store3, ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.read { transaction in - XCTAssertEqual(2, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(2, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(1, store3.numberOfKeys(transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store3.hasValue(forKey: "key0", transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertFalse(store3.hasValue(forKey: "key1", transaction: transaction)) - - XCTAssertEqual(value0, store1.getString("key0", transaction: transaction)) - XCTAssertEqual(value1, store2.getString("key0", transaction: transaction)) - XCTAssertEqual(value2, store3.getString("key0", transaction: transaction)) - XCTAssertEqual(value3, store1.getString("key1", transaction: transaction)) - XCTAssertEqual(value4, store2.getString("key1", transaction: transaction)) - XCTAssertNil(store3.getString("key1", transaction: transaction)) - } - } - - func testKeyValueDate() { - storageCoordinator.useGRDBForTests() - - let store1 = SDSKeyValueStore(collection: "store1") - let store2 = SDSKeyValueStore(collection: "store2") - let store3 = SDSKeyValueStore(collection: "store3") - - // A special store we use for date edge cases. - let store4 = SDSKeyValueStore(collection: "store4") - - let randomValue = { - return NSDate.ows_date(withMillisecondsSince1970: UInt64(arc4random())) - } - let value0 = randomValue() - let value1 = randomValue() - let value2 = randomValue() - let value3 = randomValue() - let value4 = randomValue() - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store4.numberOfKeys(transaction: transaction)) - } - - self.yapWrite { transaction in - store1.setDate(value0, key: "key0", transaction: transaction.asAnyWrite) - store2.setDate(value1, key: "key0", transaction: transaction.asAnyWrite) - store3.setDate(value2, key: "key0", transaction: transaction.asAnyWrite) - store1.setDate(value3, key: "key1", transaction: transaction.asAnyWrite) - store2.setDate(value4, key: "key1", transaction: transaction.asAnyWrite) - - // Setting as object should work. - store4.setObject(value0, key: "key0", transaction: transaction.asAnyWrite) - // Setting as timeIntervalSince1970 should work. - store4.setObject(value1.timeIntervalSince1970, key: "key1", transaction: transaction.asAnyWrite) - } - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store4.numberOfKeys(transaction: transaction)) - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBKeyValueStoreMigrator(label: "store1", keyStore: store1, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store2", keyStore: store2, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store3", keyStore: store3, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store4", keyStore: store4, ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.read { transaction in - XCTAssertEqual(2, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(2, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(1, store3.numberOfKeys(transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store3.hasValue(forKey: "key0", transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertFalse(store3.hasValue(forKey: "key1", transaction: transaction)) - - XCTAssertEqual(value0, store1.getDate("key0", transaction: transaction)) - XCTAssertEqual(value1, store2.getDate("key0", transaction: transaction)) - XCTAssertEqual(value2, store3.getDate("key0", transaction: transaction)) - XCTAssertEqual(value3, store1.getDate("key1", transaction: transaction)) - XCTAssertEqual(value4, store2.getDate("key1", transaction: transaction)) - XCTAssertNil(store3.getDate("key1", transaction: transaction)) - - // Date edge cases. - XCTAssertEqual(2, store4.numberOfKeys(transaction: transaction)) - XCTAssertTrue(store4.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store4.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertFalse(store4.hasValue(forKey: "key2", transaction: transaction)) - XCTAssertEqual(value0, store4.getDate("key0", transaction: transaction)) - XCTAssertEqual(value1, store4.getDate("key1", transaction: transaction)) - } - } - - func testKeyValueObject() { - storageCoordinator.useGRDBForTests() - - let store1 = SDSKeyValueStore(collection: "store1") - let store2 = SDSKeyValueStore(collection: "store2") - let store3 = SDSKeyValueStore(collection: "store3") - - let randomValue = { - return UUID().uuidString - } - let value0: String = randomValue() - let value1: [String] = [randomValue()] - let value2: [String: String] = [ randomValue(): randomValue() ] - let value3: [String] = [randomValue(), randomValue()] - let value4: [String: String] = [ - randomValue(): randomValue(), - randomValue(): randomValue() - ] - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - } - - self.yapWrite { transaction in - store1.setObject(value0, key: "key0", transaction: transaction.asAnyWrite) - store2.setObject(value1, key: "key0", transaction: transaction.asAnyWrite) - store3.setObject(value2, key: "key0", transaction: transaction.asAnyWrite) - store1.setObject(value3, key: "key1", transaction: transaction.asAnyWrite) - store2.setObject(value4, key: "key1", transaction: transaction.asAnyWrite) - } - - self.read { transaction in - XCTAssertEqual(0, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(0, store3.numberOfKeys(transaction: transaction)) - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBKeyValueStoreMigrator(label: "store1", keyStore: store1, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store2", keyStore: store2, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "store3", keyStore: store3, ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.read { transaction in - XCTAssertEqual(2, store1.numberOfKeys(transaction: transaction)) - XCTAssertEqual(2, store2.numberOfKeys(transaction: transaction)) - XCTAssertEqual(1, store3.numberOfKeys(transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key0", transaction: transaction)) - XCTAssertTrue(store3.hasValue(forKey: "key0", transaction: transaction)) - - XCTAssertTrue(store1.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertTrue(store2.hasValue(forKey: "key1", transaction: transaction)) - XCTAssertFalse(store3.hasValue(forKey: "key1", transaction: transaction)) - - XCTAssertEqual(value0, store1.getObject(forKey: "key0", transaction: transaction) as! String) - XCTAssertEqual(value1, store2.getObject(forKey: "key0", transaction: transaction) as! [String]) - XCTAssertEqual(value2, store3.getObject(forKey: "key0", transaction: transaction) as! [String: String]) - XCTAssertEqual(value3, store1.getObject(forKey: "key1", transaction: transaction) as! [String]) - XCTAssertEqual(value4, store2.getObject(forKey: "key1", transaction: transaction) as! [String: String]) - XCTAssertNil(store3.getObject(forKey: "key1", transaction: transaction)) - } - } -} diff --git a/Signal/test/util/YDBToGRDBMigrationModelTest.swift b/Signal/test/util/YDBToGRDBMigrationModelTest.swift deleted file mode 100644 index dc931a4230..0000000000 --- a/Signal/test/util/YDBToGRDBMigrationModelTest.swift +++ /dev/null @@ -1,862 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -import XCTest -import SignalServiceKit -@testable import Signal -@testable import SignalMessaging - -extension AnyThreadFinder { - func visibleThreadUniqueIds(isArchived: Bool, transaction: SDSAnyReadTransaction) throws -> [String] { - var result = [String]() - try enumerateVisibleThreads(isArchived: isArchived, transaction: transaction) { thread in - result.append(thread.uniqueId) - } - return result - } -} - -extension InteractionFinder { - func allInteractionIds(transaction: SDSAnyReadTransaction) throws -> [String] { - var result = [String]() - try enumerateInteractionIds(transaction: transaction) { (uniqueId, _) in - result.append(uniqueId) - } - return result - } -} - -class YDBToGRDBMigrationModelTest: SignalBaseTest { - - private let legacyDecryptJobLabel = "SSKMessageDecrypt" - - override func setUp() { - super.setUp() - - // ensure local client has necessary "registered" state - let localE164Identifier = "+13235551234" - let localUUID = UUID() - tsAccountManager.registerForTests(withLocalNumber: localE164Identifier, uuid: localUUID) - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func randomStickerPackInfo() -> StickerPackInfo { - let packId = Randomness.generateRandomBytes(16) - let packKey = Randomness.generateRandomBytes(Int32(StickerManager.packKeyLength)) - - return StickerPackInfo(packId: packId, packKey: packKey) - } - - func testSignalRecipient() { - storageCoordinator.useGRDBForTests() - - let uuid1 = UUID() - let uuid2 = UUID() - let uuid3 = UUID() - let uuid4 = UUID() - let uuid5 = UUID() - let uuid6 = UUID() - let phoneNumber1 = "+13213214321" - let phoneNumber2 = "+13213214322" - let phoneNumber3 = "+13213214323" - let phoneNumber4 = "+13213214324" - let phoneNumber5 = "+13213214325" - let phoneNumber6 = "+13213214326" - let phoneNumber7 = "+13213214327" - let deviceId0 = NSNumber(value: OWSDevicePrimaryDeviceId) - let deviceId1 = NSNumber(value: OWSDevicePrimaryDeviceId + 1) - let deviceId2 = NSNumber(value: OWSDevicePrimaryDeviceId + 2) - let model1 = SignalRecipient(phoneNumber: phoneNumber1, uuid: uuid1, devices: [deviceId0]) - let model2 = SignalRecipient(phoneNumber: phoneNumber2, uuid: uuid2, devices: [deviceId0, deviceId1]) - let model3 = SignalRecipient(phoneNumber: phoneNumber3, uuid: uuid3, devices: [deviceId0, deviceId1, deviceId2]) - // Duplicate uuid. One recipient should be discarded. - let model4a = SignalRecipient(phoneNumber: phoneNumber4, uuid: uuid4, devices: [deviceId0]) - let model4b = SignalRecipient(phoneNumber: phoneNumber5, uuid: uuid4, devices: [deviceId0]) - // Duplicate phone, unique uuid. One recipient should lose its phone number. - let model5a = SignalRecipient(phoneNumber: phoneNumber6, uuid: uuid5, devices: [deviceId0]) - let model5b = SignalRecipient(phoneNumber: phoneNumber6, uuid: uuid6, devices: [deviceId0]) - // Duplicate phone, no uuid. One recipient should be discarded. - let model6a = SignalRecipient(phoneNumber: phoneNumber7, uuid: nil, devices: [deviceId0]) - let model6b = SignalRecipient(phoneNumber: phoneNumber7, uuid: nil, devices: [deviceId0]) - - self.yapRead { transaction in - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model1.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model2.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model3.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model4a.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model4b.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model5a.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model5b.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model6a.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model6b.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertEqual(0, SignalRecipient.anyCount(transaction: transaction.asAnyRead)) - } - self.read { transaction in - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model1.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model2.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model3.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model4a.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model4b.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model5a.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model5b.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model6a.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model6b.uniqueId, transaction: transaction)) - XCTAssertEqual(0, SignalRecipient.anyCount(transaction: transaction)) - } - - self.yapWrite { transaction in - model1.anyInsert(transaction: transaction.asAnyWrite) - model2.anyInsert(transaction: transaction.asAnyWrite) - // Don't insert 3. - model4a.anyInsert(transaction: transaction.asAnyWrite) - model4b.anyInsert(transaction: transaction.asAnyWrite) - model5a.anyInsert(transaction: transaction.asAnyWrite) - model5b.anyInsert(transaction: transaction.asAnyWrite) - model6a.anyInsert(transaction: transaction.asAnyWrite) - model6b.anyInsert(transaction: transaction.asAnyWrite) - } - - self.yapRead { transaction in - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model1.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model2.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model3.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model4a.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model4b.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model5a.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model5b.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model6a.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model6b.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertEqual(8, SignalRecipient.anyCount(transaction: transaction.asAnyRead)) - } - self.read { transaction in - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model1.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model2.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model3.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model4a.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model4b.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model5a.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model5b.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model6a.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model6b.uniqueId, transaction: transaction)) - XCTAssertEqual(0, SignalRecipient.anyCount(transaction: transaction)) - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBUnorderedRecordMigrator(label: "SignalRecipient", ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.yapRead { transaction in - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model1.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model2.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model3.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model4a.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model4b.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model5a.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model5b.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model6a.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model6b.uniqueId, transaction: transaction.asAnyRead)) - XCTAssertEqual(8, SignalRecipient.anyCount(transaction: transaction.asAnyRead)) - } - self.read { transaction in - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model1.uniqueId, transaction: transaction)) - XCTAssertNotNil(SignalRecipient.anyFetch(uniqueId: model2.uniqueId, transaction: transaction)) - XCTAssertNil(SignalRecipient.anyFetch(uniqueId: model3.uniqueId, transaction: transaction)) - - // Exactly one should be migrated and one discarded. - let model4aCopy: SignalRecipient? = SignalRecipient.anyFetch(uniqueId: model4a.uniqueId, transaction: transaction) - let model4bCopy: SignalRecipient? = SignalRecipient.anyFetch(uniqueId: model4b.uniqueId, transaction: transaction) - XCTAssertTrue(model4aCopy == nil || model4bCopy == nil) - XCTAssertTrue(model4aCopy != nil || model4bCopy != nil) - - // Both should be migrated; one will no longer have a phone number. - let model5aCopy: SignalRecipient? = SignalRecipient.anyFetch(uniqueId: model5a.uniqueId, transaction: transaction) - let model5bCopy: SignalRecipient? = SignalRecipient.anyFetch(uniqueId: model5b.uniqueId, transaction: transaction) - XCTAssertNotNil(model5aCopy) - XCTAssertNotNil(model5bCopy) - XCTAssertTrue(model5aCopy?.recipientPhoneNumber == nil || model5bCopy?.recipientPhoneNumber == nil) - XCTAssertTrue(model5aCopy?.recipientPhoneNumber != nil || model5bCopy?.recipientPhoneNumber != nil) - - // Exactly one should be migrated and one discarded. - let model6aCopy: SignalRecipient? = SignalRecipient.anyFetch(uniqueId: model6a.uniqueId, transaction: transaction) - let model6bCopy: SignalRecipient? = SignalRecipient.anyFetch(uniqueId: model6b.uniqueId, transaction: transaction) - XCTAssertTrue(model6aCopy == nil || model6bCopy == nil) - XCTAssertTrue(model6aCopy != nil || model6bCopy != nil) - - XCTAssertEqual(6, SignalRecipient.anyCount(transaction: transaction)) - } - } - - func randomKnownStickerPack() -> KnownStickerPack { - return KnownStickerPack(info: randomStickerPackInfo()) - } - - func testKnownStickerPack() { - storageCoordinator.useGRDBForTests() - - let model1 = randomKnownStickerPack() - let model2 = randomKnownStickerPack() - let model3 = randomKnownStickerPack() - - self.yapRead { transaction in - XCTAssertNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model1.info), transaction: transaction.asAnyRead)) - XCTAssertNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model2.info), transaction: transaction.asAnyRead)) - XCTAssertNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model3.info), transaction: transaction.asAnyRead)) - XCTAssertEqual(0, KnownStickerPack.anyCount(transaction: transaction.asAnyRead)) - } - self.read { transaction in - XCTAssertNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model1.info), transaction: transaction)) - XCTAssertNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model2.info), transaction: transaction)) - XCTAssertNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model3.info), transaction: transaction)) - XCTAssertEqual(0, KnownStickerPack.anyCount(transaction: transaction)) - } - - self.yapWrite { transaction in - model1.anyInsert(transaction: transaction.asAnyWrite) - model2.anyInsert(transaction: transaction.asAnyWrite) - // Don't insert 3. - } - - self.yapRead { transaction in - XCTAssertNotNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model1.info), transaction: transaction.asAnyRead)) - XCTAssertNotNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model2.info), transaction: transaction.asAnyRead)) - XCTAssertNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model3.info), transaction: transaction.asAnyRead)) - XCTAssertEqual(2, KnownStickerPack.anyCount(transaction: transaction.asAnyRead)) - } - self.read { transaction in - XCTAssertNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model1.info), transaction: transaction)) - XCTAssertNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model2.info), transaction: transaction)) - XCTAssertNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model3.info), transaction: transaction)) - XCTAssertEqual(0, KnownStickerPack.anyCount(transaction: transaction)) - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBUnorderedRecordMigrator(label: "KnownStickerPack", ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.yapRead { transaction in - XCTAssertNotNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model1.info), transaction: transaction.asAnyRead)) - XCTAssertNotNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model2.info), transaction: transaction.asAnyRead)) - XCTAssertNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model3.info), transaction: transaction.asAnyRead)) - XCTAssertEqual(2, KnownStickerPack.anyCount(transaction: transaction.asAnyRead)) - } - self.read { transaction in - XCTAssertNotNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model1.info), transaction: transaction)) - XCTAssertNotNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model2.info), transaction: transaction)) - XCTAssertNil(KnownStickerPack.anyFetch(uniqueId: KnownStickerPack.uniqueId(for: model3.info), transaction: transaction)) - XCTAssertEqual(2, KnownStickerPack.anyCount(transaction: transaction)) - } - } - - func testJobs() { - storageCoordinator.useGRDBForTests() - - // SSKMessageDecryptJobRecord - let messageDecryptData1 = Randomness.generateRandomBytes(1024) - let messageDecryptData2 = Randomness.generateRandomBytes(1024) - // OWSSessionResetJobRecord - let contactThread1 = TSContactThread(contactAddress: SignalServiceAddress(phoneNumber: "+13213334444")) - let contactThread2 = TSContactThread(contactAddress: SignalServiceAddress(phoneNumber: "+13213334445")) - // SSKMessageSenderJobRecord - let outgoingMessage1 = TSOutgoingMessage(in: contactThread1, messageBody: "good heavens", attachmentId: nil) - let outgoingMessage2 = TSOutgoingMessage(in: contactThread1, messageBody: "land's sakes", attachmentId: nil) - let outgoingMessage3 = TSOutgoingMessage(in: contactThread2, messageBody: "oh my word", attachmentId: nil) - // OWSMessageDecryptJob - let messageDecryptData3 = Randomness.generateRandomBytes(1024) - let messageDecryptData4 = Randomness.generateRandomBytes(1024) - - // SSKMessageDecryptJobRecord - let messageDecryptJobFinder1 = AnyJobRecordFinder() - // OWSSessionResetJobRecord - let sessionResetJobFinder = AnyJobRecordFinder() - let sessionResetJobQueue = SessionResetJobQueue() - // SSKMessageSenderJobRecord - let messageSenderJobFinder = AnyJobRecordFinder() - let messageSenderJobQueue = MessageSenderJobQueue() - // OWSMessageDecryptJob - let messageDecryptJobFinder2 = OWSMessageDecryptJobFinder() - - self.yapRead { transaction in - // SSKMessageDecryptJobRecord - XCTAssertNil(messageDecryptJobFinder1.getNextReady(label: self.legacyDecryptJobLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(0, messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction.asAnyRead).count) - // OWSSessionResetJobRecord - XCTAssertNil(sessionResetJobFinder.getNextReady(label: sessionResetJobQueue.jobRecordLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(0, sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).count) - // SSKMessageSenderJobRecord - XCTAssertNil(messageSenderJobFinder.getNextReady(label: MessageSenderJobQueue.jobRecordLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(0, messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).count) - // OWSMessageDecryptJob - XCTAssertNil(messageDecryptJobFinder2.nextJob(transaction: transaction.asAnyRead)) - XCTAssertEqual(0, messageDecryptJobFinder2.queuedJobCount(with: transaction.asAnyRead)) - } - self.read { transaction in - // SSKMessageDecryptJobRecord - XCTAssertNil(messageDecryptJobFinder1.getNextReady(label: self.legacyDecryptJobLabel, transaction: transaction)) - XCTAssertEqual(0, messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction).count) - // OWSSessionResetJobRecord - XCTAssertNil(sessionResetJobFinder.getNextReady(label: sessionResetJobQueue.jobRecordLabel, transaction: transaction)) - XCTAssertEqual(0, sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction).count) - // SSKMessageSenderJobRecord - XCTAssertNil(messageSenderJobFinder.getNextReady(label: MessageSenderJobQueue.jobRecordLabel, transaction: transaction)) - XCTAssertEqual(0, messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction).count) - // OWSMessageDecryptJob - // - // NOTE: We don't need to verify that GRDB contains no - // OWSMessageDecryptJobs; the table doesn't even exist. - } - - self.yapWrite { transaction in - // SSKMessageDecryptJobRecord - SSKMessageDecryptJobRecord( - envelopeData: messageDecryptData1, - serverDeliveryTimestamp: NSDate.ows_millisecondTimeStamp(), - label: self.legacyDecryptJobLabel - ).anyInsert(transaction: transaction.asAnyWrite) - SSKMessageDecryptJobRecord( - envelopeData: messageDecryptData2, - serverDeliveryTimestamp: NSDate.ows_millisecondTimeStamp(), - label: self.legacyDecryptJobLabel - ).anyInsert(transaction: transaction.asAnyWrite) - - // OWSSessionResetJobRecord - sessionResetJobQueue.add(contactThread: contactThread1, transaction: transaction.asAnyWrite) - sessionResetJobQueue.add(contactThread: contactThread2, transaction: transaction.asAnyWrite) - // SSKMessageSenderJobRecord - contactThread1.anyInsert(transaction: transaction.asAnyWrite) - contactThread2.anyInsert(transaction: transaction.asAnyWrite) - outgoingMessage1.anyInsert(transaction: transaction.asAnyWrite) - outgoingMessage2.anyInsert(transaction: transaction.asAnyWrite) - outgoingMessage3.anyInsert(transaction: transaction.asAnyWrite) - messageSenderJobQueue.add(message: outgoingMessage1.asPreparer, transaction: transaction.asAnyWrite) - messageSenderJobQueue.add(message: outgoingMessage2.asPreparer, transaction: transaction.asAnyWrite) - messageSenderJobQueue.add(message: outgoingMessage3.asPreparer, transaction: transaction.asAnyWrite) - // OWSMessageDecryptJob - messageDecryptJobFinder2.addJob(forEnvelopeData: messageDecryptData3, - serverDeliveryTimestamp: NSDate.ows_millisecondTimeStamp(), - transaction: transaction.asAnyWrite) - messageDecryptJobFinder2.addJob(forEnvelopeData: messageDecryptData4, - serverDeliveryTimestamp: NSDate.ows_millisecondTimeStamp(), - transaction: transaction.asAnyWrite) - } - - self.yapRead { transaction in - // SSKMessageDecryptJobRecord - XCTAssertNotNil(messageDecryptJobFinder1.getNextReady(label: self.legacyDecryptJobLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(2, messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction.asAnyRead).count) - XCTAssertEqual([messageDecryptData1, messageDecryptData2 ], messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction.asAnyRead).compactMap { $0.envelopeData }) - // OWSSessionResetJobRecord - XCTAssertNotNil(sessionResetJobFinder.getNextReady(label: sessionResetJobQueue.jobRecordLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(2, sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).count) - XCTAssertEqual([contactThread1.uniqueId, contactThread2.uniqueId ], sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).compactMap { $0.contactThreadId }) - // SSKMessageSenderJobRecord - XCTAssertNotNil(messageSenderJobFinder.getNextReady(label: MessageSenderJobQueue.jobRecordLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(3, messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).count) - XCTAssertEqual([outgoingMessage1.uniqueId, outgoingMessage2.uniqueId, outgoingMessage3.uniqueId ], messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).compactMap { $0.messageId }) - // OWSMessageDecryptJob - XCTAssertNotNil(messageDecryptJobFinder2.nextJob(transaction: transaction.asAnyRead)) - XCTAssertEqual(2, messageDecryptJobFinder2.queuedJobCount(with: transaction.asAnyRead)) - XCTAssertEqual(messageDecryptData3, messageDecryptJobFinder2.nextJob(transaction: transaction.asAnyRead)!.envelopeData) - } - self.read { transaction in - // SSKMessageDecryptJobRecord - XCTAssertNil(messageDecryptJobFinder1.getNextReady(label: self.legacyDecryptJobLabel, transaction: transaction)) - XCTAssertEqual(0, messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction).count) - // OWSSessionResetJobRecord - XCTAssertNil(sessionResetJobFinder.getNextReady(label: sessionResetJobQueue.jobRecordLabel, transaction: transaction)) - XCTAssertEqual(0, sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction).count) - // SSKMessageSenderJobRecord - XCTAssertNil(messageSenderJobFinder.getNextReady(label: MessageSenderJobQueue.jobRecordLabel, transaction: transaction)) - XCTAssertEqual(0, messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction).count) - // OWSMessageDecryptJob - // - // NOTE: We don't need to verify that GRDB contains no - // OWSMessageDecryptJobs; the table doesn't even exist. - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBJobRecordMigrator(ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.yapRead { transaction in - // SSKMessageDecryptJobRecord - XCTAssertNotNil(messageDecryptJobFinder1.getNextReady(label: self.legacyDecryptJobLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(2, messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction.asAnyRead).count) - XCTAssertEqual([messageDecryptData1, messageDecryptData2 ], messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction.asAnyRead).compactMap { $0.envelopeData }) - // OWSSessionResetJobRecord - XCTAssertNotNil(sessionResetJobFinder.getNextReady(label: sessionResetJobQueue.jobRecordLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(2, sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).count) - XCTAssertEqual([contactThread1.uniqueId, contactThread2.uniqueId ], sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).compactMap { $0.contactThreadId }) - // SSKMessageSenderJobRecord - XCTAssertNotNil(messageSenderJobFinder.getNextReady(label: MessageSenderJobQueue.jobRecordLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(3, messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).count) - XCTAssertEqual([outgoingMessage1.uniqueId, outgoingMessage2.uniqueId, outgoingMessage3.uniqueId ], messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).compactMap { $0.messageId }) - // OWSMessageDecryptJob - XCTAssertNotNil(messageDecryptJobFinder2.nextJob(transaction: transaction.asAnyRead)) - XCTAssertEqual(2, messageDecryptJobFinder2.queuedJobCount(with: transaction.asAnyRead)) - XCTAssertEqual(messageDecryptData3, messageDecryptJobFinder2.nextJob(transaction: transaction.asAnyRead)!.envelopeData) - } - self.read { transaction in - // SSKMessageDecryptJobRecord - XCTAssertNotNil(messageDecryptJobFinder1.getNextReady(label: self.legacyDecryptJobLabel, transaction: transaction)) - XCTAssertEqual(2, messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction).count) - XCTAssertEqual([messageDecryptData1, messageDecryptData2 ], messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction).compactMap { $0.envelopeData }) - // OWSSessionResetJobRecord - XCTAssertNotNil(sessionResetJobFinder.getNextReady(label: sessionResetJobQueue.jobRecordLabel, transaction: transaction)) - XCTAssertEqual(2, sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction).count) - XCTAssertEqual([contactThread1.uniqueId, contactThread2.uniqueId ], sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction).compactMap { $0.contactThreadId }) - // SSKMessageSenderJobRecord - XCTAssertNotNil(messageSenderJobFinder.getNextReady(label: MessageSenderJobQueue.jobRecordLabel, transaction: transaction)) - XCTAssertEqual(3, messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction).count) - XCTAssertEqual([outgoingMessage1.uniqueId, outgoingMessage2.uniqueId, outgoingMessage3.uniqueId ], messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction).compactMap { $0.messageId }) - // OWSMessageDecryptJob - // - // NOTE: These jobs are _NOT_ migrated. - // See testDecryptJobs() which uses GRDBDecryptJobMigrator. - // - // NOTE: We don't need to verify that GRDB contains no - // OWSMessageDecryptJobs; the table doesn't even exist. - } - } - - func testDecryptJobs() { - storageCoordinator.useGRDBForTests() - - // SSKMessageDecryptJobRecord - let messageDecryptData1 = Randomness.generateRandomBytes(1024) - let messageDecryptData2 = Randomness.generateRandomBytes(1024) - // OWSSessionResetJobRecord - let contactThread1 = TSContactThread(contactAddress: SignalServiceAddress(phoneNumber: "+13213334444")) - let contactThread2 = TSContactThread(contactAddress: SignalServiceAddress(phoneNumber: "+13213334445")) - // SSKMessageSenderJobRecord - let outgoingMessage1 = TSOutgoingMessage(in: contactThread1, messageBody: "good heavens", attachmentId: nil) - let outgoingMessage2 = TSOutgoingMessage(in: contactThread1, messageBody: "land's sakes", attachmentId: nil) - let outgoingMessage3 = TSOutgoingMessage(in: contactThread2, messageBody: "oh my word", attachmentId: nil) - // OWSMessageDecryptJob - let messageDecryptData3 = Randomness.generateRandomBytes(1024) - let messageDecryptData4 = Randomness.generateRandomBytes(1024) - - // SSKMessageDecryptJobRecord - let messageDecryptJobFinder1 = AnyJobRecordFinder() - // OWSSessionResetJobRecord - let sessionResetJobFinder = AnyJobRecordFinder() - let sessionResetJobQueue = SessionResetJobQueue() - // SSKMessageSenderJobRecord - let messageSenderJobFinder = AnyJobRecordFinder() - let messageSenderJobQueue = MessageSenderJobQueue() - // OWSMessageDecryptJob - let messageDecryptJobFinder2 = OWSMessageDecryptJobFinder() - - self.yapRead { transaction in - // SSKMessageDecryptJobRecord - XCTAssertNil(messageDecryptJobFinder1.getNextReady(label: self.legacyDecryptJobLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(0, messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction.asAnyRead).count) - // OWSSessionResetJobRecord - XCTAssertNil(sessionResetJobFinder.getNextReady(label: sessionResetJobQueue.jobRecordLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(0, sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).count) - // SSKMessageSenderJobRecord - XCTAssertNil(messageSenderJobFinder.getNextReady(label: MessageSenderJobQueue.jobRecordLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(0, messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).count) - // OWSMessageDecryptJob - XCTAssertNil(messageDecryptJobFinder2.nextJob(transaction: transaction.asAnyRead)) - XCTAssertEqual(0, messageDecryptJobFinder2.queuedJobCount(with: transaction.asAnyRead)) - } - self.read { transaction in - // SSKMessageDecryptJobRecord - XCTAssertNil(messageDecryptJobFinder1.getNextReady(label: self.legacyDecryptJobLabel, transaction: transaction)) - XCTAssertEqual(0, messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction).count) - // OWSSessionResetJobRecord - XCTAssertNil(sessionResetJobFinder.getNextReady(label: sessionResetJobQueue.jobRecordLabel, transaction: transaction)) - XCTAssertEqual(0, sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction).count) - // SSKMessageSenderJobRecord - XCTAssertNil(messageSenderJobFinder.getNextReady(label: MessageSenderJobQueue.jobRecordLabel, transaction: transaction)) - XCTAssertEqual(0, messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction).count) - // OWSMessageDecryptJob - // - // NOTE: We don't need to verify that GRDB contains no - // OWSMessageDecryptJobs; the table doesn't even exist. - } - - self.yapWrite { transaction in - // SSKMessageDecryptJobRecord - SSKMessageDecryptJobRecord( - envelopeData: messageDecryptData1, - serverDeliveryTimestamp: NSDate.ows_millisecondTimeStamp(), - label: self.legacyDecryptJobLabel - ).anyInsert(transaction: transaction.asAnyWrite) - SSKMessageDecryptJobRecord( - envelopeData: messageDecryptData2, - serverDeliveryTimestamp: NSDate.ows_millisecondTimeStamp(), - label: self.legacyDecryptJobLabel - ).anyInsert(transaction: transaction.asAnyWrite) - - // OWSSessionResetJobRecord - sessionResetJobQueue.add(contactThread: contactThread1, transaction: transaction.asAnyWrite) - sessionResetJobQueue.add(contactThread: contactThread2, transaction: transaction.asAnyWrite) - // SSKMessageSenderJobRecord - contactThread1.anyInsert(transaction: transaction.asAnyWrite) - contactThread2.anyInsert(transaction: transaction.asAnyWrite) - outgoingMessage1.anyInsert(transaction: transaction.asAnyWrite) - outgoingMessage2.anyInsert(transaction: transaction.asAnyWrite) - outgoingMessage3.anyInsert(transaction: transaction.asAnyWrite) - messageSenderJobQueue.add(message: outgoingMessage1.asPreparer, transaction: transaction.asAnyWrite) - messageSenderJobQueue.add(message: outgoingMessage2.asPreparer, transaction: transaction.asAnyWrite) - messageSenderJobQueue.add(message: outgoingMessage3.asPreparer, transaction: transaction.asAnyWrite) - // OWSMessageDecryptJob - messageDecryptJobFinder2.addJob(forEnvelopeData: messageDecryptData3, - serverDeliveryTimestamp: NSDate.ows_millisecondTimeStamp(), - transaction: transaction.asAnyWrite) - messageDecryptJobFinder2.addJob(forEnvelopeData: messageDecryptData4, - serverDeliveryTimestamp: NSDate.ows_millisecondTimeStamp(), - transaction: transaction.asAnyWrite) - } - - self.yapRead { transaction in - // SSKMessageDecryptJobRecord - XCTAssertNotNil(messageDecryptJobFinder1.getNextReady(label: self.legacyDecryptJobLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(2, messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction.asAnyRead).count) - XCTAssertEqual([messageDecryptData1, messageDecryptData2 ], messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction.asAnyRead).compactMap { $0.envelopeData }) - // OWSSessionResetJobRecord - XCTAssertNotNil(sessionResetJobFinder.getNextReady(label: sessionResetJobQueue.jobRecordLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(2, sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).count) - XCTAssertEqual([contactThread1.uniqueId, contactThread2.uniqueId ], sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).compactMap { $0.contactThreadId }) - // SSKMessageSenderJobRecord - XCTAssertNotNil(messageSenderJobFinder.getNextReady(label: MessageSenderJobQueue.jobRecordLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(3, messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).count) - XCTAssertEqual([outgoingMessage1.uniqueId, outgoingMessage2.uniqueId, outgoingMessage3.uniqueId ], messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).compactMap { $0.messageId }) - // OWSMessageDecryptJob - XCTAssertNotNil(messageDecryptJobFinder2.nextJob(transaction: transaction.asAnyRead)) - XCTAssertEqual(2, messageDecryptJobFinder2.queuedJobCount(with: transaction.asAnyRead)) - XCTAssertEqual(messageDecryptData3, messageDecryptJobFinder2.nextJob(transaction: transaction.asAnyRead)!.envelopeData) - } - self.read { transaction in - // SSKMessageDecryptJobRecord - XCTAssertNil(messageDecryptJobFinder1.getNextReady(label: self.legacyDecryptJobLabel, transaction: transaction)) - XCTAssertEqual(0, messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction).count) - // OWSSessionResetJobRecord - XCTAssertNil(sessionResetJobFinder.getNextReady(label: sessionResetJobQueue.jobRecordLabel, transaction: transaction)) - XCTAssertEqual(0, sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction).count) - // SSKMessageSenderJobRecord - XCTAssertNil(messageSenderJobFinder.getNextReady(label: MessageSenderJobQueue.jobRecordLabel, transaction: transaction)) - XCTAssertEqual(0, messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction).count) - // OWSMessageDecryptJob - // - // NOTE: We don't need to verify that GRDB contains no - // OWSMessageDecryptJobs; the table doesn't even exist. - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBDecryptJobMigrator(ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.yapRead { transaction in - // SSKMessageDecryptJobRecord - XCTAssertNotNil(messageDecryptJobFinder1.getNextReady(label: self.legacyDecryptJobLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(2, messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction.asAnyRead).count) - XCTAssertEqual([messageDecryptData1, messageDecryptData2 ], messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction.asAnyRead).compactMap { $0.envelopeData }) - // OWSSessionResetJobRecord - XCTAssertNotNil(sessionResetJobFinder.getNextReady(label: sessionResetJobQueue.jobRecordLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(2, sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).count) - XCTAssertEqual([contactThread1.uniqueId, contactThread2.uniqueId ], sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).compactMap { $0.contactThreadId }) - // SSKMessageSenderJobRecord - XCTAssertNotNil(messageSenderJobFinder.getNextReady(label: MessageSenderJobQueue.jobRecordLabel, transaction: transaction.asAnyRead)) - XCTAssertEqual(3, messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).count) - XCTAssertEqual([outgoingMessage1.uniqueId, outgoingMessage2.uniqueId, outgoingMessage3.uniqueId ], messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction.asAnyRead).compactMap { $0.messageId }) - // OWSMessageDecryptJob - XCTAssertNotNil(messageDecryptJobFinder2.nextJob(transaction: transaction.asAnyRead)) - XCTAssertEqual(2, messageDecryptJobFinder2.queuedJobCount(with: transaction.asAnyRead)) - XCTAssertEqual(messageDecryptData3, messageDecryptJobFinder2.nextJob(transaction: transaction.asAnyRead)!.envelopeData) - } - self.read { transaction in - // SSKMessageDecryptJobRecord - // - // NOTE: These jobs are migrated from OWSMessageDecryptJob. - XCTAssertNotNil(messageDecryptJobFinder1.getNextReady(label: self.legacyDecryptJobLabel, transaction: transaction)) - XCTAssertEqual(2, messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction).count) - XCTAssertEqual([messageDecryptData3, messageDecryptData4 ], messageDecryptJobFinder1.allRecords(label: self.legacyDecryptJobLabel, status: .ready, transaction: transaction).compactMap { $0.envelopeData }) - // OWSSessionResetJobRecord - // - // NOTE: These jobs are _NOT_ migrated. - XCTAssertNil(sessionResetJobFinder.getNextReady(label: sessionResetJobQueue.jobRecordLabel, transaction: transaction)) - XCTAssertEqual(0, sessionResetJobFinder.allRecords(label: sessionResetJobQueue.jobRecordLabel, status: .ready, transaction: transaction).count) - // SSKMessageSenderJobRecord - // - // NOTE: These jobs are _NOT_ migrated. - XCTAssertNil(messageSenderJobFinder.getNextReady(label: MessageSenderJobQueue.jobRecordLabel, transaction: transaction)) - XCTAssertEqual(0, messageSenderJobFinder.allRecords(label: MessageSenderJobQueue.jobRecordLabel, status: .ready, transaction: transaction).count) - // OWSMessageDecryptJob - // - // NOTE: These jobs are migrated to SSKMessageDecryptJobRecord. - // - // NOTE: We don't need to verify that GRDB contains no - // OWSMessageDecryptJobs; the table doesn't even exist. - } - } - - func testInteractions() { - storageCoordinator.useGRDBForTests() - - // Threads - let contactThread1 = TSContactThread(contactAddress: SignalServiceAddress(phoneNumber: "+13213334444")) - let contactThread2 = TSContactThread(contactAddress: SignalServiceAddress(phoneNumber: "+13213334445")) - // Attachments - let attachmentData1 = Randomness.generateRandomBytes(1024) - let attachment1 = TSAttachmentStream(contentType: OWSMimeTypeImageGif, - byteCount: UInt32(attachmentData1.count), - sourceFilename: "some.gif", caption: nil, albumMessageId: nil) - let attachmentData2 = Randomness.generateRandomBytes(2048) - let attachment2 = TSAttachmentStream(contentType: OWSMimeTypePdf, - byteCount: UInt32(attachmentData2.count), - sourceFilename: "some.df", caption: nil, albumMessageId: nil) - // Messages - let outgoingMessage1 = TSOutgoingMessage(in: contactThread1, messageBody: "good heavens", attachmentId: attachment1.uniqueId) - let outgoingMessage2 = TSOutgoingMessage(in: contactThread2, messageBody: "land's sakes", attachmentId: attachment2.uniqueId) - let outgoingMessage3 = TSOutgoingMessage(in: contactThread2, messageBody: "oh my word", attachmentId: nil) - - self.yapRead { transaction in - XCTAssertEqual(0, TSThread.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual(0, TSInteraction.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual(0, TSAttachment.anyCount(transaction: transaction.asAnyRead)) - } - self.read { transaction in - XCTAssertEqual(0, TSThread.anyCount(transaction: transaction)) - XCTAssertEqual(0, TSInteraction.anyCount(transaction: transaction)) - XCTAssertEqual(0, TSAttachment.anyCount(transaction: transaction)) - } - - self.yapWrite { transaction in - // Threads - contactThread1.anyInsert(transaction: transaction.asAnyWrite) - contactThread2.anyInsert(transaction: transaction.asAnyWrite) - // Attachments - attachment1.anyInsert(transaction: transaction.asAnyWrite) - attachment2.anyInsert(transaction: transaction.asAnyWrite) - // Messages - outgoingMessage1.anyInsert(transaction: transaction.asAnyWrite) - outgoingMessage2.anyInsert(transaction: transaction.asAnyWrite) - outgoingMessage3.anyInsert(transaction: transaction.asAnyWrite) - } - - self.yapRead { transaction in - XCTAssertEqual(2, TSThread.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual([contactThread1.uniqueId, contactThread2.uniqueId].sorted(), TSThread.anyAllUniqueIds(transaction: transaction.asAnyRead).sorted()) - XCTAssertEqual(3, TSInteraction.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual([outgoingMessage1.uniqueId, outgoingMessage2.uniqueId, outgoingMessage3.uniqueId].sorted(), TSInteraction.anyAllUniqueIds(transaction: transaction.asAnyRead).sorted()) - XCTAssertEqual([outgoingMessage1, outgoingMessage2, outgoingMessage3].compactMap { $0.body }.sorted(), TSInteraction.anyFetchAll(transaction: transaction.asAnyRead).compactMap { ($0 as! TSMessage).body }.sorted()) - XCTAssertEqual(2, TSAttachment.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual([attachment1.uniqueId, attachment2.uniqueId].sorted(), TSAttachment.anyAllUniqueIds(transaction: transaction.asAnyRead).sorted()) - } - self.read { transaction in - XCTAssertEqual(0, TSThread.anyCount(transaction: transaction)) - XCTAssertEqual(0, TSInteraction.anyCount(transaction: transaction)) - XCTAssertEqual(0, TSAttachment.anyCount(transaction: transaction)) - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBUnorderedRecordMigrator(label: "attachments", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "threads", ydbTransaction: ydbTransaction) - ] - }, - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBInteractionMigrator(ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.yapRead { transaction in - XCTAssertEqual(2, TSThread.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual([contactThread1.uniqueId, contactThread2.uniqueId].sorted(), TSThread.anyAllUniqueIds(transaction: transaction.asAnyRead).sorted()) - XCTAssertEqual(3, TSInteraction.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual([outgoingMessage1.uniqueId, outgoingMessage2.uniqueId, outgoingMessage3.uniqueId].sorted(), TSInteraction.anyAllUniqueIds(transaction: transaction.asAnyRead).sorted()) - XCTAssertEqual([outgoingMessage1, outgoingMessage2, outgoingMessage3].compactMap { $0.body }.sorted(), TSInteraction.anyFetchAll(transaction: transaction.asAnyRead).compactMap { ($0 as! TSMessage).body }.sorted()) - XCTAssertEqual(2, TSAttachment.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual([attachment1.uniqueId, attachment2.uniqueId].sorted(), TSAttachment.anyAllUniqueIds(transaction: transaction.asAnyRead).sorted()) - } - self.read { transaction in - XCTAssertEqual(2, TSThread.anyCount(transaction: transaction)) - XCTAssertEqual([contactThread1.uniqueId, contactThread2.uniqueId].sorted(), TSThread.anyAllUniqueIds(transaction: transaction).sorted()) - XCTAssertEqual(3, TSInteraction.anyCount(transaction: transaction)) - XCTAssertEqual([outgoingMessage1.uniqueId, outgoingMessage2.uniqueId, outgoingMessage3.uniqueId].sorted(), TSInteraction.anyAllUniqueIds(transaction: transaction).sorted()) - XCTAssertEqual([outgoingMessage1, outgoingMessage2, outgoingMessage3].compactMap { $0.body }.sorted(), TSInteraction.anyFetchAll(transaction: transaction).compactMap { ($0 as! TSMessage).body }.sorted()) - XCTAssertEqual(2, TSAttachment.anyCount(transaction: transaction)) - XCTAssertEqual([attachment1.uniqueId, attachment2.uniqueId].sorted(), TSAttachment.anyAllUniqueIds(transaction: transaction).sorted()) - } - } - - func testThreadAndInteractionOrdering() { - storageCoordinator.useGRDBForTests() - - self.yapRead { transaction in - XCTAssertEqual(0, TSThread.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual(0, TSInteraction.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual(0, TSAttachment.anyCount(transaction: transaction.asAnyRead)) - } - self.read { transaction in - XCTAssertEqual(0, TSThread.anyCount(transaction: transaction)) - XCTAssertEqual(0, TSInteraction.anyCount(transaction: transaction)) - XCTAssertEqual(0, TSAttachment.anyCount(transaction: transaction)) - } - - // Threads - let contactThreadFactory = ContactThreadFactory() - let groupThreadFactory = GroupThreadFactory() - var thread1: TSThread! - var thread2: TSThread! - var thread3: TSThread! - var thread4: TSThread! - - var message1: TSInteraction! - var message2: TSInteraction! - var message3: TSInteraction! - var message4: TSInteraction! - var message5: TSInteraction! - var message6: TSInteraction! - var message7: TSInteraction! - var message8: TSInteraction! - self.yapWrite { transaction in - thread1 = contactThreadFactory.create(transaction: transaction.asAnyWrite) - thread2 = groupThreadFactory.create(transaction: transaction.asAnyWrite) - thread3 = contactThreadFactory.create(transaction: transaction.asAnyWrite) - thread4 = groupThreadFactory.create(transaction: transaction.asAnyWrite) - - // There should be 2 "group update" info messages. - XCTAssertEqual(2, TSInteraction.anyCount(transaction: transaction.asAnyRead)) - // For simplicity, remove the "group update" info messages. - do { - let interactions = TSInteraction.anyFetchAll(transaction: transaction.asAnyRead) - for interaction in interactions { - interaction.anyRemove(transaction: transaction.asAnyWrite) - } - } - - let messageFactory = IncomingMessageFactory() - - // We deliberately interleave message order across different - // threads. - - messageFactory.threadCreator = { _ in return thread1 } - message1 = messageFactory.create(transaction: transaction.asAnyWrite) - - messageFactory.threadCreator = { _ in return thread2 } - message2 = messageFactory.create(transaction: transaction.asAnyWrite) - - messageFactory.threadCreator = { _ in return thread3 } - message3 = messageFactory.create(transaction: transaction.asAnyWrite) - - messageFactory.threadCreator = { _ in return thread4 } - message4 = messageFactory.create(transaction: transaction.asAnyWrite) - - messageFactory.threadCreator = { _ in return thread1 } - message5 = messageFactory.create(transaction: transaction.asAnyWrite) - - messageFactory.threadCreator = { _ in return thread2 } - message6 = messageFactory.create(transaction: transaction.asAnyWrite) - - messageFactory.threadCreator = { _ in return thread3 } - message7 = messageFactory.create(transaction: transaction.asAnyWrite) - - messageFactory.threadCreator = { _ in return thread4 } - message8 = messageFactory.create(transaction: transaction.asAnyWrite) - } - - self.yapRead { transaction in - XCTAssertEqual(4, TSThread.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual(8, TSInteraction.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual(0, TSAttachment.anyCount(transaction: transaction.asAnyRead)) - - XCTAssertEqual(2, InteractionFinder(threadUniqueId: thread1.uniqueId).count(transaction: transaction.asAnyRead)) - XCTAssertEqual(2, InteractionFinder(threadUniqueId: thread2.uniqueId).count(transaction: transaction.asAnyRead)) - XCTAssertEqual(2, InteractionFinder(threadUniqueId: thread3.uniqueId).count(transaction: transaction.asAnyRead)) - XCTAssertEqual(2, InteractionFinder(threadUniqueId: thread4.uniqueId).count(transaction: transaction.asAnyRead)) - } - self.read { transaction in - XCTAssertEqual(0, TSThread.anyCount(transaction: transaction)) - XCTAssertEqual(0, TSInteraction.anyCount(transaction: transaction)) - XCTAssertEqual(0, TSAttachment.anyCount(transaction: transaction)) - } - - let migratorGroups = [ - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBUnorderedRecordMigrator(label: "attachments", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "threads", ydbTransaction: ydbTransaction) - ] - }, - GRDBMigratorGroup { ydbTransaction in - return [ - GRDBInteractionMigrator(ydbTransaction: ydbTransaction) - ] - } - ] - - try! YDBToGRDBMigration().migrate(migratorGroups: migratorGroups) - - self.yapRead { transaction in - XCTAssertEqual(4, TSThread.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual(8, TSInteraction.anyCount(transaction: transaction.asAnyRead)) - XCTAssertEqual(0, TSAttachment.anyCount(transaction: transaction.asAnyRead)) - - XCTAssertEqual(2, InteractionFinder(threadUniqueId: thread1.uniqueId).count(transaction: transaction.asAnyRead)) - XCTAssertEqual(2, InteractionFinder(threadUniqueId: thread2.uniqueId).count(transaction: transaction.asAnyRead)) - XCTAssertEqual(2, InteractionFinder(threadUniqueId: thread3.uniqueId).count(transaction: transaction.asAnyRead)) - XCTAssertEqual(2, InteractionFinder(threadUniqueId: thread4.uniqueId).count(transaction: transaction.asAnyRead)) - - XCTAssertEqual(4, try! AnyThreadFinder().visibleThreadCount(isArchived: false, transaction: transaction.asAnyRead)) - XCTAssertEqual([thread4.uniqueId, thread3.uniqueId, thread2.uniqueId, thread1.uniqueId ], try! AnyThreadFinder().visibleThreadUniqueIds(isArchived: false, transaction: transaction.asAnyRead)) - XCTAssertEqual([message5.uniqueId, message1.uniqueId ], try! InteractionFinder(threadUniqueId: thread1.uniqueId).allInteractionIds(transaction: transaction.asAnyRead)) - XCTAssertEqual([message6.uniqueId, message2.uniqueId ], try! InteractionFinder(threadUniqueId: thread2.uniqueId).allInteractionIds(transaction: transaction.asAnyRead)) - XCTAssertEqual([message7.uniqueId, message3.uniqueId ], try! InteractionFinder(threadUniqueId: thread3.uniqueId).allInteractionIds(transaction: transaction.asAnyRead)) - XCTAssertEqual([message8.uniqueId, message4.uniqueId ], try! InteractionFinder(threadUniqueId: thread4.uniqueId).allInteractionIds(transaction: transaction.asAnyRead)) - } - self.read { transaction in - XCTAssertEqual(4, TSThread.anyCount(transaction: transaction)) - XCTAssertEqual(8, TSInteraction.anyCount(transaction: transaction)) - XCTAssertEqual(0, TSAttachment.anyCount(transaction: transaction)) - - XCTAssertEqual(2, InteractionFinder(threadUniqueId: thread1.uniqueId).count(transaction: transaction)) - XCTAssertEqual(2, InteractionFinder(threadUniqueId: thread2.uniqueId).count(transaction: transaction)) - XCTAssertEqual(2, InteractionFinder(threadUniqueId: thread3.uniqueId).count(transaction: transaction)) - XCTAssertEqual(2, InteractionFinder(threadUniqueId: thread4.uniqueId).count(transaction: transaction)) - - XCTAssertEqual(4, try! AnyThreadFinder().visibleThreadCount(isArchived: false, transaction: transaction)) - XCTAssertEqual([thread4.uniqueId, thread3.uniqueId, thread2.uniqueId, thread1.uniqueId ], try! AnyThreadFinder().visibleThreadUniqueIds(isArchived: false, transaction: transaction)) - XCTAssertEqual([message5.uniqueId, message1.uniqueId ], try! InteractionFinder(threadUniqueId: thread1.uniqueId).allInteractionIds(transaction: transaction)) - XCTAssertEqual([message6.uniqueId, message2.uniqueId ], try! InteractionFinder(threadUniqueId: thread2.uniqueId).allInteractionIds(transaction: transaction)) - XCTAssertEqual([message7.uniqueId, message3.uniqueId ], try! InteractionFinder(threadUniqueId: thread3.uniqueId).allInteractionIds(transaction: transaction)) - XCTAssertEqual([message8.uniqueId, message4.uniqueId ], try! InteractionFinder(threadUniqueId: thread4.uniqueId).allInteractionIds(transaction: transaction)) - } - } -} diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index a5821d9e82..46d2e204cc 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -3226,6 +3226,12 @@ /* Title of the 'onboarding Captcha' view. */ "ONBOARDING_CAPTCHA_TITLE" = "Add a touch of humanity to your messages"; +/* Explanation on the 'onboarding after dropped YDB' view. */ +"ONBOARDING_DROPPED_YDB_EXPLANATION" = "Because you’ve been inactive for a long period of time, you must register again to use Signal."; + +/* Title of the 'onboarding after dropped YDB' view. */ +"ONBOARDING_DROPPED_YDB_TITLE" = "Register for Signal"; + /* button indicating that the user will register their ipad */ "ONBOARDING_MODE_SWITCH_BUTTON_PROVISIONING" = "Register iPad"; diff --git a/SignalMessaging/SignalMessaging.h b/SignalMessaging/SignalMessaging.h index 8c70b25d57..d0f8ac52ef 100644 --- a/SignalMessaging/SignalMessaging.h +++ b/SignalMessaging/SignalMessaging.h @@ -21,15 +21,6 @@ FOUNDATION_EXPORT const unsigned char SignalMessagingVersionString[]; #import #import #import -#import -#import -#import -#import -#import -#import -#import -#import -#import #import #import #import @@ -37,7 +28,6 @@ FOUNDATION_EXPORT const unsigned char SignalMessagingVersionString[]; #import #import #import -#import #import #import #import @@ -52,7 +42,6 @@ FOUNDATION_EXPORT const unsigned char SignalMessagingVersionString[]; #import #import #import -#import #import #import #import diff --git a/SignalMessaging/Views/ThreadViewHelper.m b/SignalMessaging/Views/ThreadViewHelper.m index 67c74de02d..35d59143e8 100644 --- a/SignalMessaging/Views/ThreadViewHelper.m +++ b/SignalMessaging/Views/ThreadViewHelper.m @@ -5,18 +5,15 @@ #import "ThreadViewHelper.h" #import #import -#import #import #import #import -#import #import NS_ASSUME_NONNULL_BEGIN @interface ThreadViewHelper () -@property (nonatomic, nullable) YapDatabaseViewMappings *threadMappings; @property (nonatomic) BOOL shouldObserveDBModifications; @end diff --git a/SignalMessaging/environment/AppSetup.m b/SignalMessaging/environment/AppSetup.m index a8ee647e53..1e00784cba 100644 --- a/SignalMessaging/environment/AppSetup.m +++ b/SignalMessaging/environment/AppSetup.m @@ -6,7 +6,6 @@ #import "Environment.h" #import "Theme.h" #import "VersionMigrations.h" -#import #import #import #import @@ -18,7 +17,6 @@ #import #import #import -#import #import #import #import @@ -48,10 +46,6 @@ NS_ASSUME_NONNULL_BEGIN StorageCoordinator *storageCoordinator = [StorageCoordinator new]; SDSDatabaseStorage *databaseStorage = storageCoordinator.databaseStorage; - OWSPrimaryStorage *_Nullable primaryStorage; - if (databaseStorage.canLoadYdb) { - primaryStorage = databaseStorage.yapPrimaryStorage; - } // AFNetworking (via CFNetworking) spools it's attachments to NSTemporaryDirectory(). // If you receive a media message while the device is locked, the download will fail if the temporary directory @@ -136,7 +130,6 @@ NS_ASSUME_NONNULL_BEGIN messageSenderJobQueue:messageSenderJobQueue pendingReadReceiptRecorder:pendingReadReceiptRecorder profileManager:profileManager - primaryStorage:primaryStorage networkManager:networkManager messageManager:messageManager blockingManager:blockingManager @@ -183,7 +176,6 @@ NS_ASSUME_NONNULL_BEGIN // Register renamed classes. [NSKeyedUnarchiver setClass:[OWSUserProfile class] forClassName:[OWSUserProfile collection]]; - [NSKeyedUnarchiver setClass:[OWSDatabaseMigration class] forClassName:[OWSDatabaseMigration collection]]; [NSKeyedUnarchiver setClass:[ExperienceUpgrade class] forClassName:[ExperienceUpgrade collection]]; [NSKeyedUnarchiver setClass:[ExperienceUpgrade class] forClassName:@"Signal.ExperienceUpgrade"]; [NSKeyedUnarchiver setClass:[OWSGroupInfoRequestMessage class] forClassName:@"OWSSyncGroupsRequestMessage"]; @@ -230,11 +222,7 @@ NS_ASSUME_NONNULL_BEGIN }); }; - if (databaseStorage.canLoadYdb) { - [OWSStorage registerExtensionsWithCompletionBlock:completionBlock]; - } else { - completionBlock(); - } + completionBlock(); }); } diff --git a/SignalMessaging/environment/VersionMigrations.m b/SignalMessaging/environment/VersionMigrations.m index 02b421702d..3a2c8f67c1 100644 --- a/SignalMessaging/environment/VersionMigrations.m +++ b/SignalMessaging/environment/VersionMigrations.m @@ -4,17 +4,14 @@ #import "VersionMigrations.h" #import "Environment.h" -#import "OWSDatabaseMigrationRunner.h" #import #import #import #import -#import #import #import #import #import -#import NS_ASSUME_NONNULL_BEGIN @@ -43,52 +40,10 @@ NS_ASSUME_NONNULL_BEGIN if (!lastCompletedLaunchAppVersion) { OWSLogInfo(@"No previous version found. Probably first launch since install - nothing to migrate."); - if (self.databaseStorage.canReadFromGrdb) { - [self.databaseStorage runGrdbSchemaMigrationsWithCompletion:completion]; - } else { - OWSDatabaseMigrationRunner *runner = [OWSDatabaseMigrationRunner new]; - [runner assumeAllExistingMigrationsRun]; - dispatch_async(dispatch_get_main_queue(), completion); - } - return; } - if ([self isVersion:lastCompletedLaunchAppVersion atLeast:@"1.0.2" andLessThan:@"2.0"]) { - OWSLogError(@"Migrating from RedPhone no longer supported. Quitting."); - // Not translating these as so few are affected. - ActionSheetController *actionSheet = [[ActionSheetController alloc] - initWithTitle:@"You must reinstall Signal" - message:@"Sorry, your installation is too old for us to update. You'll have to start fresh."]; - - ActionSheetAction *quitAction = [[ActionSheetAction alloc] initWithTitle:@"Quit" - style:ActionSheetActionStyleDefault - handler:^(ActionSheetAction *_Nonnull action) { - OWSFail(@"Obsolete install."); - }]; - [actionSheet addAction:quitAction]; - - [CurrentAppContext().frontmostViewController presentActionSheet:actionSheet]; - } - - if ([self isVersion:lastCompletedLaunchAppVersion atLeast:@"2.0.0" andLessThan:@"2.1.70"] && - [self.tsAccountManager isRegistered]) { - [self clearVideoCache]; - } - - if ([self isVersion:lastCompletedLaunchAppVersion atLeast:@"2.0.0" andLessThan:@"2.3.0"] && - [self.tsAccountManager isRegistered]) { - [self clearBloomFilterCache]; - } - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - if (self.databaseStorage.canReadFromGrdb) { - [self.databaseStorage runGrdbSchemaMigrationsWithCompletion:completion]; - } else { - [[[OWSDatabaseMigrationRunner alloc] init] runAllOutstandingWithCompletion:^{ - completion(); - }]; - } - }); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + ^{ [self.databaseStorage runGrdbSchemaMigrationsWithCompletion:completion]; }); } + (BOOL)isVersion:(NSString *)thisVersionString @@ -109,55 +64,6 @@ NS_ASSUME_NONNULL_BEGIN return [thisVersionString compare:thatVersionString options:NSNumericSearch] == NSOrderedAscending; } -#pragma mark Upgrading to 2.1 - Removing video cache folder - -+ (void)clearVideoCache -{ - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil; - basePath = [basePath stringByAppendingPathComponent:@"videos"]; - - NSError *error; - if ([[NSFileManager defaultManager] fileExistsAtPath:basePath]) { - [NSFileManager.defaultManager removeItemAtPath:basePath error:&error]; - } - - if (error) { - OWSLogError( - @"An error occured while removing the videos cache folder from old location: %@", error.debugDescription); - } -} - -#pragma mark Upgrading to 2.3.0 - -// We removed bloom filter contact discovery. Clean up any local bloom filter data. -+ (void)clearBloomFilterCache -{ - NSFileManager *fm = [NSFileManager defaultManager]; - NSArray *cachesDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - NSString *bloomFilterPath = [[cachesDir objectAtIndex:0] stringByAppendingPathComponent:@"bloomfilter"]; - - if ([fm fileExistsAtPath:bloomFilterPath]) { - NSError *deleteError; - if ([fm removeItemAtPath:bloomFilterPath error:&deleteError]) { - OWSLogInfo(@"Successfully removed bloom filter cache."); - - if (self.databaseStorage.canLoadYdb) { - [OWSPrimaryStorage.dbReadWriteConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [transaction removeAllObjectsInCollection:@"TSRecipient"]; - }]; - OWSLogInfo( - @"Removed all TSRecipient records - will be replaced by SignalRecipients at next address sync."); - } - } else { - OWSLogError(@"Failed to remove bloom filter cache with error: %@", deleteError.localizedDescription); - } - } else { - OWSLogDebug(@"No bloom filter cache to remove."); - } -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS100RemoveTSRecipientsMigration.h b/SignalMessaging/environment/migrations/OWS100RemoveTSRecipientsMigration.h deleted file mode 100644 index 92768e55bf..0000000000 --- a/SignalMessaging/environment/migrations/OWS100RemoveTSRecipientsMigration.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSDatabaseMigration.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWS100RemoveTSRecipientsMigration : YDBDatabaseMigration - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS100RemoveTSRecipientsMigration.m b/SignalMessaging/environment/migrations/OWS100RemoveTSRecipientsMigration.m deleted file mode 100644 index 4ca6451ca1..0000000000 --- a/SignalMessaging/environment/migrations/OWS100RemoveTSRecipientsMigration.m +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWS100RemoveTSRecipientsMigration.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -// Increment a similar constant for every future DBMigration -static NSString *const OWS100RemoveTSRecipientsMigrationId = @"100"; - -@implementation OWS100RemoveTSRecipientsMigration - -+ (NSString *)migrationId -{ - return OWS100RemoveTSRecipientsMigrationId; -} - -- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - NSUInteger legacyRecipientCount = [transaction numberOfKeysInCollection:@"TSRecipient"]; - OWSLogWarn(@"Removing %lu objects from TSRecipient collection", (unsigned long)legacyRecipientCount); - [transaction removeAllObjectsInCollection:@"TSRecipient"]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS101ExistingUsersBlockOnIdentityChange.h b/SignalMessaging/environment/migrations/OWS101ExistingUsersBlockOnIdentityChange.h deleted file mode 100644 index c1ae1443aa..0000000000 --- a/SignalMessaging/environment/migrations/OWS101ExistingUsersBlockOnIdentityChange.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSDatabaseMigration.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWS101ExistingUsersBlockOnIdentityChange : YDBDatabaseMigration - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS101ExistingUsersBlockOnIdentityChange.m b/SignalMessaging/environment/migrations/OWS101ExistingUsersBlockOnIdentityChange.m deleted file mode 100644 index 7e195335a5..0000000000 --- a/SignalMessaging/environment/migrations/OWS101ExistingUsersBlockOnIdentityChange.m +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWS101ExistingUsersBlockOnIdentityChange.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -// Increment a similar constant for every future DBMigration -static NSString *const OWS101ExistingUsersBlockOnIdentityChangeMigrationId = @"101"; - -/** - * This migration is no longer necessary, but deleting a class is complicated in Yap - * and involves writing another migration to remove the previous. It seemed like the - * simplest/safest thing to do would be to just leave it. - */ -@implementation OWS101ExistingUsersBlockOnIdentityChange - -+ (NSString *)migrationId -{ - return OWS101ExistingUsersBlockOnIdentityChangeMigrationId; -} - -- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - OWSFailDebug(@"[OWS101ExistingUsersBlockOnIdentityChange] has been obviated."); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS102MoveLoggingPreferenceToUserDefaults.h b/SignalMessaging/environment/migrations/OWS102MoveLoggingPreferenceToUserDefaults.h deleted file mode 100644 index ac2107f29a..0000000000 --- a/SignalMessaging/environment/migrations/OWS102MoveLoggingPreferenceToUserDefaults.h +++ /dev/null @@ -1,9 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSDatabaseMigration.h" - -@interface OWS102MoveLoggingPreferenceToUserDefaults : YDBDatabaseMigration - -@end diff --git a/SignalMessaging/environment/migrations/OWS102MoveLoggingPreferenceToUserDefaults.m b/SignalMessaging/environment/migrations/OWS102MoveLoggingPreferenceToUserDefaults.m deleted file mode 100644 index 9f0747748b..0000000000 --- a/SignalMessaging/environment/migrations/OWS102MoveLoggingPreferenceToUserDefaults.m +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWS102MoveLoggingPreferenceToUserDefaults.h" -#import "DebugLogger.h" -#import "Environment.h" -#import "OWSPreferences.h" -#import - -// Increment a similar constant for every future DBMigration -static NSString *const OWS102MoveLoggingPreferenceToUserDefaultsMigrationId = @"102"; - -@implementation OWS102MoveLoggingPreferenceToUserDefaults - -+ (NSString *)migrationId -{ - return OWS102MoveLoggingPreferenceToUserDefaultsMigrationId; -} - -- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - OWSLogWarn(@"[OWS102MoveLoggingPreferenceToUserDefaultsMigrationId] copying existing logging preference to " - @"NSUserDefaults"); - - NSNumber *_Nullable existingValue = - [transaction objectForKey:OWSPreferencesKeyEnableDebugLog inCollection:OWSPreferencesSignalDatabaseCollection]; - - if (existingValue) { - OWSLogInfo(@"assigning existing value: %@", existingValue); - [OWSPreferences setIsLoggingEnabled:[existingValue boolValue]]; - - if (![existingValue boolValue]) { - OWSLogInfo(@"Disabling file logger after one-time log settings migration."); - // Since we're migrating, we didn't have the appropriate value on startup, and incorrectly started logging. - [DebugLogger.sharedLogger disableFileLogging]; - } else { - OWSLogInfo(@"Continuing to log after one-time log settings migration."); - } - } else { - OWSLogInfo(@"not assigning any value, since no previous value was stored."); - } -} - -@end diff --git a/SignalMessaging/environment/migrations/OWS103EnableVideoCalling.h b/SignalMessaging/environment/migrations/OWS103EnableVideoCalling.h deleted file mode 100644 index 23e5a89167..0000000000 --- a/SignalMessaging/environment/migrations/OWS103EnableVideoCalling.h +++ /dev/null @@ -1,9 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSDatabaseMigration.h" - -@interface OWS103EnableVideoCalling : YDBDatabaseMigration - -@end diff --git a/SignalMessaging/environment/migrations/OWS103EnableVideoCalling.m b/SignalMessaging/environment/migrations/OWS103EnableVideoCalling.m deleted file mode 100644 index cc1c69cfd8..0000000000 --- a/SignalMessaging/environment/migrations/OWS103EnableVideoCalling.m +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import "OWS103EnableVideoCalling.h" -#import -#import -#import -#import -#import - -// Increment a similar constant for every future DBMigration -static NSString *const OWS103EnableVideoCallingMigrationId = @"103"; - -@implementation OWS103EnableVideoCalling - -+ (NSString *)migrationId -{ - return OWS103EnableVideoCallingMigrationId; -} - -// Override parent migration -- (void)runUpWithCompletion:(OWSDatabaseMigrationCompletion)completion -{ - OWSAssertDebug(completion); - - OWSLogWarn(@"running migration..."); - if ([self.tsAccountManager isRegistered]) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - TSRequest *request = [OWSRequestFactory updatePrimaryDeviceAttributesRequest]; - [[TSNetworkManager shared] makeRequest:request - success:^(NSURLSessionDataTask *task, id responseObject) { - OWSLogInfo(@"successfully ran"); - [self markAsCompleteWithSneakyTransaction]; - - completion(); - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - if (!IsNetworkConnectivityFailure(error)) { - OWSProdError([OWSAnalyticsEvents errorEnableVideoCallingRequestFailed]); - } - OWSLogError(@"failed with error: %@", error); - - completion(); - }]; - }); - } else { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - OWSLogInfo(@"skipping; not registered"); - [self markAsCompleteWithSneakyTransaction]; - - completion(); - }); - } -} - -@end diff --git a/SignalMessaging/environment/migrations/OWS104CreateRecipientIdentities.h b/SignalMessaging/environment/migrations/OWS104CreateRecipientIdentities.h deleted file mode 100644 index 56eb104178..0000000000 --- a/SignalMessaging/environment/migrations/OWS104CreateRecipientIdentities.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSDatabaseMigration.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWS104CreateRecipientIdentities : YDBDatabaseMigration - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS104CreateRecipientIdentities.m b/SignalMessaging/environment/migrations/OWS104CreateRecipientIdentities.m deleted file mode 100644 index a8d5447fa1..0000000000 --- a/SignalMessaging/environment/migrations/OWS104CreateRecipientIdentities.m +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWS104CreateRecipientIdentities.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -// Increment a similar constant for every future DBMigration -static NSString *const OWS104CreateRecipientIdentitiesMigrationId = @"104"; - -/** - * New SN behavior requires tracking additional state - not just the identity key data. - * So we wrap the key, along with the new meta-data in an OWSRecipientIdentity. - */ -@implementation OWS104CreateRecipientIdentities - -+ (NSString *)migrationId -{ - return OWS104CreateRecipientIdentitiesMigrationId; -} - -- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - NSMutableDictionary *identityKeys = [NSMutableDictionary new]; - - NSString *const OWSPrimaryStorageTrustedKeysCollection = @"TSStorageManagerTrustedKeysCollection"; - [transaction - enumerateKeysAndObjectsInCollection:OWSPrimaryStorageTrustedKeysCollection - usingBlock:^(NSString *_Nonnull recipientId, id _Nonnull object, BOOL *_Nonnull stop) { - if (![object isKindOfClass:[NSData class]]) { - OWSFailDebug( - @"Unexpected object in trusted keys collection key: %@ object: %@", - recipientId, - [object class]); - return; - } - NSData *identityKey = (NSData *)object; - [identityKeys setObject:identityKey forKey:recipientId]; - }]; - - [identityKeys enumerateKeysAndObjectsUsingBlock:^( - NSString *_Nonnull recipientId, NSData *_Nonnull identityKey, BOOL *_Nonnull stop) { - OWSLogInfo(@"Migrating identity key for recipient: %@", recipientId); - OWSRecipientIdentity *recipientIdentity = - [[OWSRecipientIdentity alloc] initWithAccountId:recipientId - identityKey:identityKey - isFirstKnownKey:NO - createdAt:[NSDate dateWithTimeIntervalSince1970:0] - verificationState:OWSVerificationStateDefault]; - // All pre-GRDB migrations should be YAP-only. - [recipientIdentity ydb_saveWithTransaction:transaction]; - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS105AttachmentFilePaths.h b/SignalMessaging/environment/migrations/OWS105AttachmentFilePaths.h deleted file mode 100644 index 0f28fffb8f..0000000000 --- a/SignalMessaging/environment/migrations/OWS105AttachmentFilePaths.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSDatabaseMigration.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWS105AttachmentFilePaths : YDBDatabaseMigration - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS105AttachmentFilePaths.m b/SignalMessaging/environment/migrations/OWS105AttachmentFilePaths.m deleted file mode 100644 index 57b3e61c46..0000000000 --- a/SignalMessaging/environment/migrations/OWS105AttachmentFilePaths.m +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWS105AttachmentFilePaths.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -// Increment a similar constant for every future DBMigration -static NSString *const OWS105AttachmentFilePathsMigrationId = @"105"; - -@implementation OWS105AttachmentFilePaths - -+ (NSString *)migrationId -{ - return OWS105AttachmentFilePathsMigrationId; -} - -- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - NSMutableArray *attachmentStreams = [NSMutableArray new]; - [transaction enumerateKeysAndObjectsInCollection:TSAttachmentStream.collection - usingBlock:^(NSString *key, TSAttachment *attachment, BOOL *stop) { - if (![attachment isKindOfClass:[TSAttachmentStream class]]) { - return; - } - TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment; - [attachmentStreams addObject:attachmentStream]; - }]; - - OWSLogInfo(@"Saving %lu attachment streams.", (unsigned long)attachmentStreams.count); - - // Persist the new localRelativeFilePath property of TSAttachmentStream. - // For performance, we want to upgrade all existing attachment streams in - // a single transaction. - for (TSAttachmentStream *attachmentStream in attachmentStreams) { - // NOTE: Use legacy save. - [attachmentStream ydb_saveWithTransaction:transaction]; - } -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS106EnsureProfileComplete.swift b/SignalMessaging/environment/migrations/OWS106EnsureProfileComplete.swift deleted file mode 100644 index a5ba916f22..0000000000 --- a/SignalMessaging/environment/migrations/OWS106EnsureProfileComplete.swift +++ /dev/null @@ -1,117 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -import Foundation -import PromiseKit -import SignalServiceKit - -@objc -public class OWS106EnsureProfileComplete: YDBDatabaseMigration { - - private static var sharedCompleteRegistrationFixerJob: CompleteRegistrationFixerJob? - - // increment a similar constant for each migration. - @objc - public override class var migrationId: String { - return "106" - } - - // Overriding runUp since we have some specific completion criteria which - // is more likely to fail since it involves network requests. - override public func runUp(completion:@escaping () -> Void) { - let job = CompleteRegistrationFixerJob(completionHandler: { (didSucceed) in - - if didSucceed { - Logger.info("Completed. Saving.") - - self.markAsCompleteWithSneakyTransaction() - } else { - Logger.error("Failed.") - } - - completion() - }) - - type(of: self).sharedCompleteRegistrationFixerJob = job - - job.start() - } - - /** - * A previous client bug made it possible for re-registering users to register their new account - * but never upload new pre-keys. The symptom is that there will be accounts with no uploaded - * identity key. We detect that here and fix the situation - */ - private class CompleteRegistrationFixerJob: NSObject { - - // Duration between retries if update fails. - let kRetryInterval: TimeInterval = 5 - - let completionHandler: (Bool) -> Void - - init(completionHandler: @escaping (Bool) -> Void) { - self.completionHandler = completionHandler - } - - func start() { - guard tsAccountManager.isRegistered else { - self.completionHandler(true) - return - } - - self.ensureProfileComplete().done { - Logger.info("complete. Canceling timer and saving.") - self.completionHandler(true) - }.catch { error in - let nserror = error as NSError - if nserror.domain == TSNetworkManagerErrorDomain { - // Don't retry if we had an unrecoverable error. - // In particular, 401 (invalid auth) is unrecoverable. - let isUnrecoverableError = nserror.code == 401 - if isUnrecoverableError { - Logger.error("failed due to unrecoverable error: \(error). Aborting.") - self.completionHandler(true) - return - } - } - - Logger.error("failed with \(error).") - self.completionHandler(false) - } - } - - func ensureProfileComplete() -> Promise { - guard let localAddress = TSAccountManager.localAddress, localAddress.isValid else { - // local app doesn't think we're registered, so nothing to worry about. - return Promise.value(()) - } - - return firstly { - return ProfileFetcherJob.fetchProfilePromise(address: localAddress, - ignoreThrottling: true) - }.done { _ in - Logger.info("verified recipient profile is in good shape: \(localAddress)") - }.recover { error -> Promise in - switch error { - case SignalServiceProfile.ValidationError.invalidIdentityKey(let description): - Logger.warn("detected incomplete profile for \(localAddress) error: \(description)") - - let (promise, resolver) = Promise.pending() - // This is the error condition we're looking for. Update prekeys to properly set the identity key, completing registration. - TSPreKeyManager.createPreKeys(success: { - Logger.info("successfully uploaded pre-keys. Profile should be fixed.") - resolver.fulfill(()) - }, - failure: { _ in - resolver.reject(OWSErrorWithCodeDescription(.signalServiceFailure, "\(self.logTag) Unknown error")) - }) - - return promise - default: - throw error - } - } - } - } -} diff --git a/SignalMessaging/environment/migrations/OWS107LegacySounds.h b/SignalMessaging/environment/migrations/OWS107LegacySounds.h deleted file mode 100644 index fc6e905914..0000000000 --- a/SignalMessaging/environment/migrations/OWS107LegacySounds.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSDatabaseMigration.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWS107LegacySounds : YDBDatabaseMigration - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS107LegacySounds.m b/SignalMessaging/environment/migrations/OWS107LegacySounds.m deleted file mode 100644 index 13e27f134a..0000000000 --- a/SignalMessaging/environment/migrations/OWS107LegacySounds.m +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. -// - -#import "OWS107LegacySounds.h" -#import "OWSSounds.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -// Increment a similar constant for every future DBMigration -static NSString *const OWS107LegacySoundsMigrationId = @"107"; - -@implementation OWS107LegacySounds - -+ (NSString *)migrationId -{ - return OWS107LegacySoundsMigrationId; -} - -- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - [OWSSounds setGlobalNotificationSound:OWSStandardSound_SignalClassic transaction:transaction.asAnyWrite]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS108CallLoggingPreference.h b/SignalMessaging/environment/migrations/OWS108CallLoggingPreference.h deleted file mode 100644 index f7454bf2a6..0000000000 --- a/SignalMessaging/environment/migrations/OWS108CallLoggingPreference.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSDatabaseMigration.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWS108CallLoggingPreference : YDBDatabaseMigration - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS108CallLoggingPreference.m b/SignalMessaging/environment/migrations/OWS108CallLoggingPreference.m deleted file mode 100644 index 3eee45eb93..0000000000 --- a/SignalMessaging/environment/migrations/OWS108CallLoggingPreference.m +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import "OWS108CallLoggingPreference.h" -#import "Environment.h" -#import "OWSPreferences.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -// Increment a similar constant for every future DBMigration -static NSString *const OWS108CallLoggingPreferenceId = @"108"; - -@implementation OWS108CallLoggingPreference - -+ (NSString *)migrationId -{ - return OWS108CallLoggingPreferenceId; -} - -- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - [self.preferences applyCallLoggingSettingsForLegacyUsersWithTransaction:transaction]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS109OutgoingMessageState.h b/SignalMessaging/environment/migrations/OWS109OutgoingMessageState.h deleted file mode 100644 index 6b6b23c5ec..0000000000 --- a/SignalMessaging/environment/migrations/OWS109OutgoingMessageState.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSResaveCollectionDBMigration.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWS109OutgoingMessageState : OWSResaveCollectionDBMigration - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS109OutgoingMessageState.m b/SignalMessaging/environment/migrations/OWS109OutgoingMessageState.m deleted file mode 100644 index d108abb503..0000000000 --- a/SignalMessaging/environment/migrations/OWS109OutgoingMessageState.m +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import "OWS109OutgoingMessageState.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -// Increment a similar constant for every future DBMigration -static NSString *const OWS109OutgoingMessageStateMigrationId = @"109"; - -@implementation OWS109OutgoingMessageState - -+ (NSString *)migrationId -{ - return OWS109OutgoingMessageStateMigrationId; -} - -// Override parent migration -- (void)runUpWithCompletion:(OWSDatabaseMigrationCompletion)completion -{ - OWSAssertDebug(completion); - - OWSDatabaseConnection *dbConnection = (OWSDatabaseConnection *)self.primaryStorage.newDatabaseConnection; - - [self resaveDBCollection:TSOutgoingMessage.collection - filter:^(id entity) { - return [entity isKindOfClass:[TSOutgoingMessage class]]; - } - dbConnection:dbConnection - completion:^{ - [self markAsCompleteWithSneakyTransaction]; - - completion(); - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWS110SortIdMigration.swift b/SignalMessaging/environment/migrations/OWS110SortIdMigration.swift deleted file mode 100644 index 40eb244ee4..0000000000 --- a/SignalMessaging/environment/migrations/OWS110SortIdMigration.swift +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. -// - -import Foundation - -public class OWS110SortIdMigration: YDBDatabaseMigration { - // increment a similar constant for each migration. - @objc - public override class var migrationId: String { - // append char "x" because we want to rerun on some internal devices which - // have already run this migration. - return "110x" - } - - override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) { - Logger.debug("") - BenchAsync(title: "Sort Migration") { completeBenchmark in - self.doMigration { - completeBenchmark() - completion() - } - } - } - - private func doMigration(completion: @escaping OWSDatabaseMigrationCompletion) { - // TODO batch this? - self.ydbReadWriteConnection.readWrite { transaction in - - var archivedThreads: [TSThread] = [] - - // get archived threads before migration - TSThread.ydb_enumerateCollectionObjects(with: transaction) { (object, _) in - guard let thread = object as? TSThread else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - - if thread.isArchivedByLegacyTimestampForSorting { - archivedThreads.append(thread) - } - } - - guard let legacySorting = transaction.safeAutoViewTransaction(TSMessageDatabaseViewExtensionName_Legacy) else { - owsFailDebug("legacySorting was unexpectedly nil") - return - } - - let totalCount: UInt = legacySorting.numberOfItemsInAllGroups() - var completedCount: UInt = 0 - - var allGroups = [String]() - legacySorting.enumerateGroups { group, _ in - allGroups.append(group) - } - - var seenGroups: Set = Set() - for group in allGroups { - autoreleasepool { - // Sanity Check #1 - // Make sure our enumeration is monotonically increasing. - // Note: sortIds increase monotonically WRT timestampForLegacySorting, but only WRT the interaction's thread. - // - // e.g. When we migrate the **next** thread, we start with that thread's oldest interaction. So it's possible and expected - // that thread2's oldest interaction will have a smaller timestampForLegacySorting, but a greater sortId then an interaction - // in thread1. That's OK because we only sort messages with respect to the thread they belong in. We don't have any sort of - // "global sort" of messages across all threads. - var previousTimestampForLegacySorting: UInt64 = 0 - - // Sanity Check #2 - // Ensure we only process a DB View's group (i.e. threadId) once. - guard !seenGroups.contains(group) else { - owsFail("unexpectedly seeing a repeated group: \(group)") - } - seenGroups.insert(group) - - var groupKeys = [String]() - legacySorting.enumerateKeys(inGroup: group, using: { (_, key, _, _) in - groupKeys.append(key) - }) - let groupKeyBatchSize: Int = 1024 - for batch in groupKeys.chunked(by: groupKeyBatchSize) { - autoreleasepool { - for uniqueId in batch { - guard let interaction = TSInteraction.ydb_fetch(uniqueId: uniqueId, transaction: transaction) else { - owsFailDebug("Could not load interaction: \(uniqueId)") - return - } - if interaction.timestampForLegacySorting() < previousTimestampForLegacySorting { - owsFailDebug("unexpected object ordering previousTimestampForLegacySorting: \(previousTimestampForLegacySorting) interaction.timestampForLegacySorting: \(interaction.timestampForLegacySorting())") - } - previousTimestampForLegacySorting = interaction.timestampForLegacySorting() - - interaction.ydb_saveNextSortId(transaction: transaction) - - completedCount += 1 - if completedCount % 100 == 0 { - // Legit usage of legacy sorting for migration to new sorting - Logger.info("thread: \(interaction.uniqueThreadId), timestampForLegacySorting:\(interaction.timestampForLegacySorting()), sortId: \(interaction.sortId) totalCount: \(totalCount), completedcount: \(completedCount)") - } - } - } - } - } - } - - Logger.info("re-archiving \(archivedThreads.count) threads which were previously archived") - for archivedThread in archivedThreads { - archivedThread.archiveThread(updateStorageService: false, transaction: transaction.asAnyWrite) - } - - self.markAsComplete(with: transaction.asAnyWrite) - } - - completion() - } - -} diff --git a/SignalMessaging/environment/migrations/OWS111UDAttributesMigration.swift b/SignalMessaging/environment/migrations/OWS111UDAttributesMigration.swift deleted file mode 100644 index a8c6d59db2..0000000000 --- a/SignalMessaging/environment/migrations/OWS111UDAttributesMigration.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalServiceKit -import PromiseKit - -@objc -public class OWS111UDAttributesMigration: YDBDatabaseMigration { - - // increment a similar constant for each migration. - @objc - public override class var migrationId: String { - // NOTE: Changes were made to the service after this migration was initially - // merged, so we need to re-migrate any developer devices. - return "111.1" - } - - override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) { - Logger.debug("") - Bench(title: "UD Attributes Migration") { - self.doMigration() - } - completion() - } - - private func doMigration() { - firstly { - tsAccountManager.updateAccountAttributes() - }.catch { error in - owsFailDebug("Error: \(error)") - } - - self.ydbReadWriteConnection.readWrite { transaction in - self.markAsComplete(with: transaction.asAnyWrite) - } - } -} diff --git a/SignalMessaging/environment/migrations/OWS112TypingIndicatorsMigration.swift b/SignalMessaging/environment/migrations/OWS112TypingIndicatorsMigration.swift deleted file mode 100644 index f35729cafc..0000000000 --- a/SignalMessaging/environment/migrations/OWS112TypingIndicatorsMigration.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalServiceKit - -@objc -public class OWS112TypingIndicatorsMigration: YDBDatabaseMigration { - - // Increment a similar constant for each migration. - @objc - public override class var migrationId: String { - return "112" - } - - override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) { - Logger.debug("") - BenchAsync(title: "Typing Indicators Migration") { (benchCompletion) in - self.doMigrationAsync(completion: { - benchCompletion() - completion() - }) - } - } - - private func doMigrationAsync(completion : @escaping OWSDatabaseMigrationCompletion) { - DispatchQueue.main.async { - // Typing indicators should be disabled by default for - // legacy users. - self.typingIndicatorsImpl.setTypingIndicatorsEnabledAndSendSyncMessage(value: false) - - DispatchQueue.global().async { - self.markAsCompleteWithSneakyTransaction() - - completion() - } - } - } -} diff --git a/SignalMessaging/environment/migrations/OWS113MultiAttachmentMediaMessages.swift b/SignalMessaging/environment/migrations/OWS113MultiAttachmentMediaMessages.swift deleted file mode 100644 index 615254be00..0000000000 --- a/SignalMessaging/environment/migrations/OWS113MultiAttachmentMediaMessages.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalServiceKit - -@objc -public class OWS113MultiAttachmentMediaMessages: YDBDatabaseMigration { - - // Increment a similar constant for each migration. - @objc - public override class var migrationId: String { - // NOTE: that we use .1 since there was a bug in the logic to - // set albumMessageId. - return "113.1" - } - - override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) { - Logger.debug("") - BenchAsync(title: "\(self.logTag)") { (benchCompletion) in - self.doMigrationAsync(completion: { - benchCompletion() - completion() - }) - } - } - - private func doMigrationAsync(completion : @escaping OWSDatabaseMigrationCompletion) { - DispatchQueue.global().async { - var legacyAttachments: [(attachmentId: String, messageId: String)] = [] - - self.ydbReadWriteConnection.read { transaction in - TSMessage.ydb_enumerateCollectionObjects(with: transaction) { object, _ in - autoreleasepool { - guard let message: TSMessage = object as? TSMessage else { - Logger.debug("ignoring message with type: \(object)") - return - } - - let messageId = message.uniqueId - for attachmentId in message.attachmentIds { - legacyAttachments.append((attachmentId: attachmentId, messageId: messageId)) - } - } - } - } - self.ydbReadWriteConnection.readWrite { transaction in - for (attachmentId, messageId) in legacyAttachments { - autoreleasepool { - // NOTE: Use legacy fetch. - guard let attachment = TSAttachment.ydb_fetch(uniqueId: attachmentId, transaction: transaction) else { - Logger.warn("missing attachment for messageId: \(messageId)") - return - } - - attachment.migrateAlbumMessageId(messageId) - // NOTE: Use legacy save. - attachment.ydb_save(with: transaction) - } - } - self.markAsComplete(with: transaction.asAnyWrite) - } - - completion() - } - } -} diff --git a/SignalMessaging/environment/migrations/OWS114RemoveDynamicInteractions.swift b/SignalMessaging/environment/migrations/OWS114RemoveDynamicInteractions.swift deleted file mode 100644 index 444cb19c7d..0000000000 --- a/SignalMessaging/environment/migrations/OWS114RemoveDynamicInteractions.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalServiceKit - -@objc -public class OWS114RemoveDynamicInteractions: YDBDatabaseMigration { - - // Increment a similar constant for each migration. - @objc - public override class var migrationId: String { - return "114" - } - - override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) { - Logger.debug("") - BenchAsync(title: "\(self.logTag)") { (benchCompletion) in - self.doMigrationAsync(completion: { - benchCompletion() - completion() - }) - } - } - - private func doMigrationAsync(completion : @escaping OWSDatabaseMigrationCompletion) { - DispatchQueue.global().async { - self.ydbReadWriteConnection.readWrite { transaction in - guard let dbView = TSDatabaseView.threadSpecialMessagesDatabaseView(transaction) as? YapDatabaseViewTransaction else { - owsFailDebug("Couldn't load db view.") - return - } - - var interactionsToDelete = [TSInteraction]() - let groupIds = dbView.allGroups() - for groupId in groupIds { - dbView.enumerateKeysAndObjects(inGroup: groupId) { (_: String, _: String, object: Any, _: UInt, _: UnsafeMutablePointer) in - guard let interaction = object as? TSInteraction else { - owsFailDebug("Invalid database entity: \(type(of: object)).") - return - } - guard interaction.isDynamicInteraction() else { - return - } - interactionsToDelete.append(interaction) - } - } - - for interaction in interactionsToDelete { - Logger.debug("Cleaning up interaction: \(type(of: interaction)).") - interaction.ydb_remove(with: transaction) - } - - self.markAsComplete(with: transaction.asAnyWrite) - } - - completion() - } - } -} diff --git a/SignalMessaging/environment/migrations/OWS115CleanupProfileAvatars.swift b/SignalMessaging/environment/migrations/OWS115CleanupProfileAvatars.swift deleted file mode 100644 index c732642868..0000000000 --- a/SignalMessaging/environment/migrations/OWS115CleanupProfileAvatars.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalServiceKit - -@objc -public class OWS115EnsureProfileAvatars: YDBDatabaseMigration { - - // Increment a similar constant for each migration. - @objc - public override class var migrationId: String { - return "115" - } - - var fileManager: FileManager { - return FileManager.default - } - - override public func runUp(with transaction: YapDatabaseReadWriteTransaction) { - Bench(title: "\(self.logTag)") { - var profilesWithMissingAvatars: [String] = [] - OWSUserProfile.anyEnumerate(transaction: transaction.asAnyWrite, - batched: true) { profile, _ in - guard let filename = profile.avatarFileName else { - return - } - - let filepath = OWSUserProfile.profileAvatarFilepath(withFilename: filename) - guard !self.fileManager.fileExists(atPath: filepath) else { - return - } - profilesWithMissingAvatars.append(profile.uniqueId) - } - - for uniqueId in profilesWithMissingAvatars { - guard let profile = OWSUserProfile.anyFetch(uniqueId: uniqueId, transaction: transaction.asAnyRead) else { - owsFailDebug("profile was unexpectedly nil") - continue - } - Logger.info("removing reference to non-existant avatar file") - profile.update(withAvatarFileName: nil, transaction: transaction.asAnyWrite) - } - } - } -} diff --git a/SignalMessaging/environment/migrations/OWS116UpdatePrekeys.swift b/SignalMessaging/environment/migrations/OWS116UpdatePrekeys.swift deleted file mode 100644 index dd93170a15..0000000000 --- a/SignalMessaging/environment/migrations/OWS116UpdatePrekeys.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalServiceKit - -@objc -public class OWS116UpdatePrekeys: YDBDatabaseMigration { - - // Increment a similar constant for each migration. - @objc - public override class var migrationId: String { - return "116" - } - - override public func runUp(with transaction: YapDatabaseReadWriteTransaction) { - Bench(title: "\(self.logTag)") { - let keyStore = self.preKeyStore.keyStore - do { - var keys: [String] = keyStore.allKeys(transaction: transaction.asAnyRead) - try Batching.loop(batchSize: Batching.kDefaultBatchSize, - loopBlock: { stop in - guard let key = keys.popLast() else { - stop.pointee = true - return - } - guard let record = keyStore.getObject(forKey: key, transaction: transaction.asAnyRead) as? PreKeyRecord else { - owsFailDebug("Missing record.") - return - } - guard record.createdAt == nil else { - owsFailDebug("Unexpected createdAt.") - return - } - record.setCreatedAtToNow() - keyStore.setObject(record, key: key, transaction: transaction.asAnyWrite) - }) - } catch { - owsFail("Migration failed.") - } - } - } -} diff --git a/SignalMessaging/environment/migrations/OWS1XXGRDBMigration.swift b/SignalMessaging/environment/migrations/OWS1XXGRDBMigration.swift deleted file mode 100644 index 2600b6c8d3..0000000000 --- a/SignalMessaging/environment/migrations/OWS1XXGRDBMigration.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import GRDB -import SignalServiceKit - -extension StorageCoordinatorState: CustomStringConvertible { - public var description: String { - return NSStringFromStorageCoordinatorState(self) - } -} - -@objc -public class OWS1XXGRDBMigration: YDBDatabaseMigration { - - // Increment a similar constant for each migration. - @objc - public override class var migrationId: String { - return "1XX" - } - - override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) { - Logger.debug("") - - DispatchQueue.global().async { - if self.storageCoordinator.state != .beforeYDBToGRDBMigration { - owsFail("unexpected storage coordinator state: \(self.storageCoordinator.state)") - } else { - - self.databaseStorage.write { transaction in - do { - // We need to dedupe the recipients *before* migrating to - // GRDB since GRDB enforces uniqueness constraints on SignalRecipients. - try dedupeSignalRecipients(transaction: transaction) - } catch { - // we don't bother failing hard here. - // If for some reason duplicates remain, then the YDBToGRDBMigration will - // fail hard anyway. And conversely, if it doesn't fail then there were - // no duplicate SignalRecipients. - owsFailDebug("error: \(error)") - } - } - - self.storageCoordinator.migrationYDBToGRDBWillBegin() - assert(self.storageCoordinator.state == .duringYDBToGRDBMigration) - - Bench(title: "\(self.logTag)") { - do { - try YDBToGRDBMigration().run() - } catch { - owsFail("error: \(error)") - } - } - - self.storageCoordinator.migrationYDBToGRDBDidComplete() - assert(self.storageCoordinator.state == .GRDB) - } - - self.databaseStorage.write { transaction in - switch transaction.writeTransaction { - case .grdbWrite: - self.markAsComplete(with: transaction) - case .yapWrite: - owsFail("wrong transaction type") - } - } - - completion() - } - } - - public override var shouldBeSaved: Bool { - if SDSDatabaseStorage.shouldUseDisposableGrdb { - // Do nothing so as to re-run every launch. - // Useful while actively developing the migration. - return false - } else { - return true - } - } -} diff --git a/SignalMessaging/environment/migrations/OWSDatabaseMigration.h b/SignalMessaging/environment/migrations/OWSDatabaseMigration.h deleted file mode 100644 index 21c34d5ba8..0000000000 --- a/SignalMessaging/environment/migrations/OWSDatabaseMigration.h +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -typedef void (^OWSDatabaseMigrationCompletion)(void); - -@class OWSPrimaryStorage; -@class SDSAnyReadTransaction; -@class SDSAnyWriteTransaction; -@class SDSKeyValueStore; -@class YapDatabaseConnection; -@class YapDatabaseReadWriteTransaction; - -// Although OWSDatabaseMigration is still a TSYapDatabaseObject -// to enable deserialization of legacy values, OWSDatabaseMigration -// now uses a key-value store to persist migration completion. -// -// Therefore, we do _not_ need to subclass BaseModel here. -@interface OWSDatabaseMigration : TSYapDatabaseObject - -+ (SDSKeyValueStore *)keyValueStore; - -@property (class, nonatomic, readonly) NSString *migrationId; -@property (nonatomic, readonly) NSString *migrationId; - -// Prefer nonblocking (async) migrations by overriding `runUpWithTransaction:` in a subclass. -// Blocking migrations running too long will crash the app, effectively bricking install -// because the user will never get past it. -// If you must write a launch-blocking migration, override runUp. -- (void)runUpWithCompletion:(OWSDatabaseMigrationCompletion)completion; - -- (void)markAsCompleteWithTransaction:(SDSAnyWriteTransaction *)transaction; - -+ (void)markMigrationIdAsComplete:(NSString *)migrationId transaction:(SDSAnyWriteTransaction *)transaction; - -+ (void)markMigrationIdAsIncomplete:(NSString *)migrationId transaction:(SDSAnyWriteTransaction *)transaction; - -- (void)markAsCompleteWithSneakyTransaction; - -// We use a sneaky transaction since YDBDatabaseMigration will -// want to consult YDB and GRDBDatabaseMigration will want to -// consult GRDB. -- (BOOL)isCompleteWithSneakyTransaction; - -+ (NSArray *)allCompleteMigrationIdsWithTransaction:(SDSAnyReadTransaction *)transaction; - -@end - -#pragma mark - - -// A base class for migrations run before the YDB-to-GRDB migration. -// These migrations are run against the YDB store. -@interface YDBDatabaseMigration : OWSDatabaseMigration - -// Subclasses should override this convenience method or runUpWithCompletion. -- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; - -#pragma mark - Database Connections - -@property (nonatomic, readonly) YapDatabaseConnection *ydbReadWriteConnection; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWSDatabaseMigration.m b/SignalMessaging/environment/migrations/OWSDatabaseMigration.m deleted file mode 100644 index 909a2c130a..0000000000 --- a/SignalMessaging/environment/migrations/OWSDatabaseMigration.m +++ /dev/null @@ -1,161 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSDatabaseMigration - -// This key-value store is used to persist completion of migrations. -// Note that it uses the YDB collection previously used to persist migration models. -// Since we just check "has key", this is backwards-compatible. -+ (SDSKeyValueStore *)keyValueStore -{ - static SDSKeyValueStore *keyValueStore = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - keyValueStore = [[SDSKeyValueStore alloc] initWithCollection:OWSDatabaseMigration.collection]; - }); - return keyValueStore; -} - -- (instancetype)init -{ - return [super initWithUniqueId:[self.class migrationId]]; -} - -#pragma mark - - -+ (NSString *)migrationId -{ - OWSAbstractMethod(); - - return @""; -} - -- (NSString *)migrationId -{ - return self.class.migrationId; -} - -+ (NSString *)collection -{ - // We want all subclasses in the same collection - return @"OWSDatabaseMigration"; -} - -- (void)runUpWithCompletion:(OWSDatabaseMigrationCompletion)completion -{ - OWSAbstractMethod(); -} - -- (void)markAsCompleteWithTransaction:(SDSAnyWriteTransaction *)transaction -{ - if (!self.shouldBeSaved) { - OWSLogInfo(@"NOT Marking migration as incomplete: %@ %@", [self class], self.migrationId); - return; - } - - [OWSDatabaseMigration markMigrationIdAsComplete:self.migrationId transaction:transaction]; -} - -+ (void)markMigrationIdAsComplete:(NSString *)migrationId transaction:(SDSAnyWriteTransaction *)transaction -{ - OWSLogInfo(@"Marking migration as complete: %@", migrationId); - - [self.keyValueStore setBool:YES key:migrationId transaction:transaction]; -} - -+ (void)markMigrationIdAsIncomplete:(NSString *)migrationId transaction:(SDSAnyWriteTransaction *)transaction -{ - OWSLogInfo(@"Marking migration as incomplete: %@", migrationId); - - [self.keyValueStore removeValueForKey:migrationId transaction:transaction]; -} - -- (void)markAsCompleteWithSneakyTransaction -{ - DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) { - [self markAsCompleteWithTransaction:transaction]; - }); -} - -- (BOOL)isCompleteWithSneakyTransaction -{ - __block BOOL result; - [self.databaseStorage readWithBlock:^(SDSAnyReadTransaction *transaction) { - result = [self isCompleteWithTransaction:transaction]; - }]; - return result; -} - -- (BOOL)isCompleteWithTransaction:(SDSAnyReadTransaction *)transaction -{ - return [OWSDatabaseMigration.keyValueStore hasValueForKey:self.migrationId transaction:transaction]; -} - -+ (NSArray *)allCompleteMigrationIdsWithTransaction:(SDSAnyReadTransaction *)transaction -{ - return [self.keyValueStore allKeysWithTransaction:transaction]; -} - -@end - -#pragma mark - - -@implementation YDBDatabaseMigration - -- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAbstractMethod(); -} - -- (void)runUpWithCompletion:(OWSDatabaseMigrationCompletion)completion -{ - OWSAssertDebug(completion); - - OWSDatabaseConnection *dbConnection = (OWSDatabaseConnection *)self.primaryStorage.newDatabaseConnection; - - [dbConnection - asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [self runUpWithTransaction:transaction]; - } - completionBlock:^{ - [dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self markAsCompleteWithTransaction:transaction.asAnyWrite]; - }]; - - completion(); - }]; -} - -#pragma mark - Database Connections - -+ (YapDatabaseConnection *)ydbReadConnection -{ - return self.ydbReadWriteConnection; -} - -+ (YapDatabaseConnection *)ydbReadWriteConnection -{ - return SSKEnvironment.shared.migrationDBConnection; -} - -- (YapDatabaseConnection *)ydbReadConnection -{ - return YDBDatabaseMigration.ydbReadConnection; -} - -- (YapDatabaseConnection *)ydbReadWriteConnection -{ - return YDBDatabaseMigration.ydbReadWriteConnection; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.h b/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.h deleted file mode 100644 index 82e658a1f2..0000000000 --- a/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -typedef void (^OWSDatabaseMigrationCompletion)(void); - -@interface OWSDatabaseMigrationRunner : NSObject - -/** - * Run any outstanding version migrations. - */ -- (void)runAllOutstandingWithCompletion:(OWSDatabaseMigrationCompletion)completion; - -/** - * On new installations, no need to migrate anything. - */ -- (void)assumeAllExistingMigrationsRun; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m b/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m deleted file mode 100644 index 5f205adc72..0000000000 --- a/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m +++ /dev/null @@ -1,134 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import "OWSDatabaseMigrationRunner.h" -#import "OWS100RemoveTSRecipientsMigration.h" -#import "OWS102MoveLoggingPreferenceToUserDefaults.h" -#import "OWS103EnableVideoCalling.h" -#import "OWS104CreateRecipientIdentities.h" -#import "OWS105AttachmentFilePaths.h" -#import "OWS107LegacySounds.h" -#import "OWS108CallLoggingPreference.h" -#import "OWS109OutgoingMessageState.h" -#import "OWSDatabaseMigration.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSDatabaseMigrationRunner - -// This should all migrations which do NOT qualify as safeBlockingMigrations: -- (NSArray *)allMigrations -{ - NSArray *prodMigrations = @[ - [[OWS100RemoveTSRecipientsMigration alloc] init], - [[OWS102MoveLoggingPreferenceToUserDefaults alloc] init], - [[OWS103EnableVideoCalling alloc] init], - [[OWS104CreateRecipientIdentities alloc] init], - [[OWS105AttachmentFilePaths alloc] init], - [[OWS106EnsureProfileComplete alloc] init], - [[OWS107LegacySounds alloc] init], - [[OWS108CallLoggingPreference alloc] init], - [[OWS109OutgoingMessageState alloc] init], - [OWS110SortIdMigration new], - [[OWS111UDAttributesMigration alloc] init], - [[OWS112TypingIndicatorsMigration alloc] init], - [[OWS113MultiAttachmentMediaMessages alloc] init], - [[OWS114RemoveDynamicInteractions alloc] init], - [OWS115EnsureProfileAvatars new], - [OWS116UpdatePrekeys new] - ]; - - if (StorageCoordinator.dataStoreForUI == DataStoreGrdb) { - return [prodMigrations arrayByAddingObjectsFromArray:@ [[OWS1XXGRDBMigration new]]]; - } else { - return prodMigrations; - } -} - -- (void)assumeAllExistingMigrationsRun -{ - DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) { - for (OWSDatabaseMigration *migration in self.allMigrations) { - OWSLogInfo(@"Skipping migration on new install: %@", migration); - - [migration markAsCompleteWithTransaction:transaction]; - } - }); -} - -- (void)runAllOutstandingWithCompletion:(OWSDatabaseMigrationCompletion)completion -{ - [self removeUnknownMigrations]; - - [self runMigrations:[self.allMigrations mutableCopy] completion:completion]; -} - -// Some users (especially internal users) will move back and forth between -// app versions. Whenever they move "forward" in the version history, we -// want them to re-run any new migrations. Therefore, when they move "backward" -// in the version history, we cull any unknown migrations. -- (void)removeUnknownMigrations -{ - NSMutableSet *knownMigrationIds = [NSMutableSet new]; - for (OWSDatabaseMigration *migration in self.allMigrations) { - [knownMigrationIds addObject:migration.migrationId]; - } - - DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) { - NSArray *savedMigrationIds = - [OWSDatabaseMigration allCompleteMigrationIdsWithTransaction:transaction]; - - NSMutableSet *unknownMigrationIds = [NSMutableSet new]; - [unknownMigrationIds addObjectsFromArray:savedMigrationIds]; - [unknownMigrationIds minusSet:knownMigrationIds]; - - for (NSString *unknownMigrationId in unknownMigrationIds) { - OWSLogInfo(@"Culling unknown migration: %@", unknownMigrationId); - [OWSDatabaseMigration markMigrationIdAsIncomplete:unknownMigrationId transaction:transaction]; - } - }); -} - -// Run migrations serially to: -// -// * Ensure predictable ordering. -// * Prevent them from interfering with each other (e.g. deadlock). -- (void)runMigrations:(NSMutableArray *)migrations - completion:(OWSDatabaseMigrationCompletion)completion -{ - OWSAssertDebug(migrations); - OWSAssertDebug(completion); - - // If there are no more migrations to run, complete. - if (migrations.count < 1) { - dispatch_async(dispatch_get_main_queue(), ^{ - completion(); - }); - return; - } - - // Pop next migration from front of queue. - OWSDatabaseMigration *migration = migrations.firstObject; - [migrations removeObjectAtIndex:0]; - - // If migration has already been run, skip it. - if (migration.isCompleteWithSneakyTransaction) { - [self runMigrations:migrations completion:completion]; - return; - } - - OWSLogInfo(@"Running migration: %@ %@", migration, migration.migrationId); - - [migration runUpWithCompletion:^{ - OWSLogInfo(@"Migration complete: %@ %@", migration, migration.migrationId); - - [self runMigrations:migrations completion:completion]; - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWSResaveCollectionDBMigration.h b/SignalMessaging/environment/migrations/OWSResaveCollectionDBMigration.h deleted file mode 100644 index bdaab74850..0000000000 --- a/SignalMessaging/environment/migrations/OWSResaveCollectionDBMigration.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSDatabaseMigration.h" - -NS_ASSUME_NONNULL_BEGIN - -typedef BOOL (^DBRecordFilterBlock)(id record); - -@class YapDatabaseConnection; - -// Base class for migrations that resave all or a subset of -// records in a database collection. -@interface OWSResaveCollectionDBMigration : YDBDatabaseMigration - -- (void)resaveDBCollection:(NSString *)collection - filter:(nullable DBRecordFilterBlock)filter - dbConnection:(YapDatabaseConnection *)dbConnection - completion:(OWSDatabaseMigrationCompletion)completion; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/OWSResaveCollectionDBMigration.m b/SignalMessaging/environment/migrations/OWSResaveCollectionDBMigration.m deleted file mode 100644 index ffd952d021..0000000000 --- a/SignalMessaging/environment/migrations/OWSResaveCollectionDBMigration.m +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSResaveCollectionDBMigration.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation OWSResaveCollectionDBMigration - -- (void)resaveDBCollection:(NSString *)collection - filter:(nullable DBRecordFilterBlock)filter - dbConnection:(YapDatabaseConnection *)dbConnection - completion:(OWSDatabaseMigrationCompletion)completion -{ - OWSAssertDebug(collection.length > 0); - OWSAssertDebug(dbConnection); - OWSAssertDebug(completion); - - NSMutableArray *recordIds = [NSMutableArray new]; - [dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [recordIds addObjectsFromArray:[transaction allKeysInCollection:collection]]; - OWSLogInfo(@"Migrating %lu records from: %@.", (unsigned long)recordIds.count, collection); - } - completionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) - completionBlock:^{ - [self resaveBatch:recordIds - collection:collection - filter:filter - dbConnection:dbConnection - completion:completion]; - }]; -} - -- (void)resaveBatch:(NSMutableArray *)recordIds - collection:(NSString *)collection - filter:(nullable DBRecordFilterBlock)filter - dbConnection:(YapDatabaseConnection *)dbConnection - completion:(OWSDatabaseMigrationCompletion)completion -{ - OWSAssertDebug(recordIds); - OWSAssertDebug(collection.length > 0); - OWSAssertDebug(dbConnection); - OWSAssertDebug(completion); - - OWSLogVerbose(@"%lu", (unsigned long)recordIds.count); - - if (recordIds.count < 1) { - completion(); - return; - } - - [dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - const int kBatchSize = 1000; - for (int i = 0; i < kBatchSize && recordIds.count > 0; i++) { - NSString *messageId = [recordIds lastObject]; - [recordIds removeLastObject]; - id record = [transaction objectForKey:messageId inCollection:collection]; - if (filter && !filter(record)) { - continue; - } - TSYapDatabaseObject *entity = (TSYapDatabaseObject *)record; - [entity ydb_saveWithTransaction:transaction]; - } - } - completionBlock:^{ - // Process the next batch. - [self resaveBatch:recordIds - collection:collection - filter:filter - dbConnection:dbConnection - completion:completion]; - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/PrivateMethodsForMigration.h b/SignalMessaging/environment/migrations/PrivateMethodsForMigration.h deleted file mode 100644 index 5a6b41bb27..0000000000 --- a/SignalMessaging/environment/migrations/PrivateMethodsForMigration.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - - -// We need access to this for migration purposes - -@class SDSKeyValueStore; - -@interface SSKSessionStore (PrivateMethodsForMigration) - -@property (nonatomic, readonly) SDSKeyValueStore *keyValueStore; - -@end - -@interface SSKPreKeyStore (PrivateMethodsForMigration) - -@property (nonatomic, readonly) SDSKeyValueStore *keyStore; -@property (nonatomic, readonly) SDSKeyValueStore *metadataStore; - -@end - -@interface SSKSignedPreKeyStore (PrivateMethodsForMigration) - -@property (nonatomic, readonly) SDSKeyValueStore *keyStore; -@property (nonatomic, readonly) SDSKeyValueStore *metadataStore; - -@end - -@interface OWSIdentityManager (PrivateMethodsForMigration) - -@property (nonatomic, readonly) SDSKeyValueStore *ownIdentityKeyValueStore; -@property (nonatomic, readonly) SDSKeyValueStore *queuedVerificationStateSyncMessagesKeyValueStore; - -@end - -@interface TSAccountManager (PrivateMethodsForMigration) - -@property (nonatomic, readonly) SDSKeyValueStore *keyValueStore; - -@end - - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/environment/migrations/YDBToGRDBMigration.swift b/SignalMessaging/environment/migrations/YDBToGRDBMigration.swift deleted file mode 100644 index 95ecf11a90..0000000000 --- a/SignalMessaging/environment/migrations/YDBToGRDBMigration.swift +++ /dev/null @@ -1,731 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -import Foundation -import GRDB -import SignalServiceKit - -@objc -public class YDBToGRDBMigration: NSObject { - - // MARK: - Other key stores - - // This migration class resides in SignalMessaging. It ensures that we - // migrate an kv stores in SignalMessaging or its dependency SSK. - // - // However it doesn't know about any key-value stores defined in the - // Signal (or hypothetically the SignalShareExtension) target(s). - // So the migration logic needs to be informed of those stores. - private static var otherKeyStores = [String: SDSKeyValueStore]() - - @objc - public class func add(keyStore: SDSKeyValueStore, - label: String) { - AssertIsOnMainThread() - - guard otherKeyStores[label] == nil else { - owsFailDebug("Keystore added twice.") - return - } - otherKeyStores[label] = keyStore - } -} - -// MARK: - - -@objc -public class GRDBMigratorGroup: NSObject { - public typealias MigratorBlock = (YapDatabaseReadTransaction) -> [GRDBMigrator] - public typealias CompletionBlock = () -> Void - - private let block: MigratorBlock - - fileprivate let completionBlock: CompletionBlock? - - @objc - public required init(completionBlock: CompletionBlock? = nil, - block: @escaping MigratorBlock) { - self.block = block - self.completionBlock = completionBlock - } - - func migrators(ydbTransaction: YapDatabaseReadTransaction) -> [GRDBMigrator] { - return block(ydbTransaction) - } -} - -// MARK: - - -extension YDBToGRDBMigration { - - func run() throws { - Logger.info("") - - let startDate = Date() - - // We migrate the data store contents in phases - // or batches. Each "group" defines the data to - // migrate in a given batch. - let migratorGroups = [ - // Migrate the key-value and unordered records first; - // The later migrations may use these values in - // "sneaky" transactions. - GRDBMigratorGroup { ydbTransaction in - return self.allKeyValueMigrators(ydbTransaction: ydbTransaction) - }, - // We need to migrate the user profiles before other models since they - // are used when indexing various other models. - GRDBMigratorGroup(completionBlock: { - self.profileManager.warmCaches() - }) { ydbTransaction in - return self.profileRecordMigrators(ydbTransaction: ydbTransaction) - }, - GRDBMigratorGroup { ydbTransaction in - return self.allUnorderedRecordMigrators(ydbTransaction: ydbTransaction) - }, - GRDBMigratorGroup { ydbTransaction in - return [GRDBJobRecordMigrator(ydbTransaction: ydbTransaction)] - }, - GRDBMigratorGroup { ydbTransaction in - return [GRDBInteractionMigrator(ydbTransaction: ydbTransaction)] - }, - GRDBMigratorGroup { ydbTransaction in - return [GRDBDecryptJobMigrator(ydbTransaction: ydbTransaction)] - } - ] - - GRDBSchemaMigrator().runSchemaMigrations() - - try self.migrate(migratorGroups: migratorGroups) - - try grdbStorageAdapter.write { transaction in - do { - try createInitialGalleryRecords(transaction: transaction) - } catch { - owsFail("error: \(error)") - } - } - - removeYdb() - - let migrationDuration = abs(startDate.timeIntervalSinceNow) - Logger.info("Migration duration: \(OWSFormat.formatDurationSeconds(Int(migrationDuration))) (\(migrationDuration))") - } - - func removeYdb() { - guard FeatureFlags.storageMode != .grdbThrowawayIfMigrating else { - return - } - - // Don't set this flag for "throwaway" migrations. - // - // It's critical that we do this _before_ deleting the YDB contents, - // since the GRDB database is considered disposable until this flag - // is set if there are YDB files. - SSKPreferences.setIsYdbMigrated(true) - - guard let primaryStorage = primaryStorage else { - owsFail("Missing primaryStorage.") - } - let ydbReadConnection = primaryStorage.newDatabaseConnection() - if let owsDatabaseConnection = ydbReadConnection as? OWSDatabaseConnection { - // Bless this connection to make YDB writes despite migration - // being complete. - owsDatabaseConnection.isCleanupConnection = true - } else { - owsFailDebug("Unexpected connection type.") - } - ydbReadConnection.readWrite { ydbTransaction in - // Note: we deliberately _DO NOT_ deserialize the - // models as we delete them from YDB. That would - // have undesired side effects, e.g. deleting - // attachments on disk. - ydbTransaction.removeAllObjectsInAllCollections() - } - - OWSStorage.deleteDBKeys() - OWSStorage.deleteDatabaseFiles() - } - - func migrate(migratorGroups: [GRDBMigratorGroup]) throws { - Logger.info("") - - // We can't nest ydbTransactions in GRDB and vice-versa - // each has their own serial-queue based concurrency model, which wants to be on - // _their own_ serial queue. - // - // GRDB at least supports nesting multiple database transactions, but the _both_ - // have to be accessed via GRDB - // - // TODO: see if we can get reasonable perf by avoiding the nested transactions and - // instead doing work in non-overlapping batches. - guard let primaryStorage = primaryStorage else { - owsFail("Missing primaryStorage.") - } - let ydbReadConnection = primaryStorage.newDatabaseConnection() - ydbReadConnection.ignoreQueues = true - ydbReadConnection.beginLongLivedReadTransaction() - - UIDatabaseObserver.serializedSync { - UIDatabaseObserver.skipTouchObservations = true - } - - for migratorGroup in migratorGroups { - try migrate(migratorGroup: migratorGroup, - ydbReadConnection: ydbReadConnection) - } - - UIDatabaseObserver.serializedSync { - UIDatabaseObserver.skipTouchObservations = false - } - } - - private func migrate(migratorGroup: GRDBMigratorGroup, - ydbReadConnection: YapDatabaseConnection) throws { - Logger.info("") - - // Logging queries is helpful for normal debugging, but expensive during a migration - SDSDatabaseStorage.shouldLogDBQueries = false - - try ydbReadConnection.read { ydbTransaction in - let migrators = migratorGroup.migrators(ydbTransaction: ydbTransaction) - // Migrate migrators. - for migrator in migrators { - try autoreleasepool { - try self.grdbStorageAdapter.write { grdbTransaction in - try! migrator.migrate(grdbTransaction: grdbTransaction) - } - } - } - } - - if let completionBlock = migratorGroup.completionBlock { - completionBlock() - } - - SDSDatabaseStorage.shouldLogDBQueries = DebugFlags.logSQLQueries - } - - private func allKeyValueMigrators(ydbTransaction: YapDatabaseReadTransaction) -> [GRDBMigrator] { - LegacySessionRecord.setUpKeyedArchiverSubstitutions() - var result: [GRDBMigrator] = [ - GRDBKeyValueStoreMigrator(label: "preKey Store", keyStore: preKeyStore.keyStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "preKey Metadata", keyStore: preKeyStore.metadataStore, ydbTransaction: ydbTransaction), - - GRDBKeyValueStoreMigrator(label: "signedPreKey Store", keyStore: signedPreKeyStore.keyStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "signedPreKey Metadata", keyStore: signedPreKeyStore.metadataStore, ydbTransaction: ydbTransaction), - - GRDBKeyValueStoreMigrator(label: "ownIdentity", keyStore: identityManager.ownIdentityKeyValueStore, ydbTransaction: ydbTransaction), - - GRDBKeyValueStoreMigrator<[Int: LegacySessionRecord]>(label: "sessionStore", keyStore: sessionStore.keyValueStore, ydbTransaction: ydbTransaction), - - GRDBKeyValueStoreMigrator(label: "queuedVerificationStateSyncMessages", keyStore: identityManager.queuedVerificationStateSyncMessagesKeyValueStore, ydbTransaction: ydbTransaction), - - GRDBKeyValueStoreMigrator(label: "tsAccountManager", keyStore: tsAccountManager.keyValueStore, ydbTransaction: ydbTransaction), - - GRDBKeyValueStoreMigrator(label: "AppPreferences", keyStore: AppPreferences.store, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "SSKPreferences", keyStore: SSKPreferences.store, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "StickerManager.store", keyStore: StickerManager.store, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "StickerManager.emojiMapStore", keyStore: StickerManager.emojiMapStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "preferences", keyStore: Self.preferences.keyValueStore, ydbTransaction: ydbTransaction), - - GRDBKeyValueStoreMigrator(label: "OWSOrphanDataCleaner", keyStore: OWSOrphanDataCleaner.keyValueStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "contactsManager", keyStore: contactsManagerImpl.keyValueStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSDeviceManager", keyStore: OWSDeviceManager.keyValueStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSReadReceiptManager", keyStore: OWSReadReceiptManager.keyValueStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWS2FAManager", keyStore: OWS2FAManager.keyValueStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSBlockingManager", keyStore: OWSBlockingManager.keyValueStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "typingIndicators", keyStore: typingIndicatorsImpl.keyValueStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "udManager.keyValueStore", keyStore: udManager.keyValueStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "udManager.phoneNumberAccessStore", keyStore: udManager.phoneNumberAccessStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "udManager.uuidAccessStore", keyStore: udManager.uuidAccessStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "CallKitIdStore.phoneNumber", keyStore: CallKitIdStore.phoneNumber(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "CallKitIdStore.uuid", keyStore: CallKitIdStore.uuidStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "signalService", keyStore: signalService.keyValueStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSStorageServiceOperation", keyStore: StorageServiceOperation.keyValueStore, ydbTransaction: ydbTransaction), - - GRDBKeyValueStoreMigrator(label: "OWSDatabaseMigration", keyStore: OWSDatabaseMigration.keyValueStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSProfileManager.whitelistedPhoneNumbersStore", keyStore: profileManagerImpl.whitelistedPhoneNumbersStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSProfileManager.whitelistedUUIDsStore", keyStore: profileManagerImpl.whitelistedUUIDsStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSProfileManager.whitelistedGroupsStore", keyStore: profileManagerImpl.whitelistedGroupsStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSProfileManager.settingsStore", keyStore: OWSProfileManager.settingsStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSScreenLock.keyValueStore", keyStore: OWSScreenLock.shared.keyValueStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSSounds", keyStore: OWSSounds.keyValueStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "Theme", keyStore: Theme.keyValueStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSSyncManager", keyStore: OWSSyncManager.keyValueStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSOutgoingReceiptManager.deliveryReceiptStore", keyStore: OWSOutgoingReceiptManager.deliveryReceiptStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "OWSOutgoingReceiptManager.readReceiptStore", keyStore: OWSOutgoingReceiptManager.readReceiptStore(), ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "VersionedProfiles.credentialStore", keyStore: VersionedProfilesImpl.credentialStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "KeyBackupService.keyValueStore", keyStore: KeyBackupService.keyValueStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "KeyBackupService.tokenStore", keyStore: KeyBackupService.tokenStore, ydbTransaction: ydbTransaction), - GRDBKeyValueStoreMigrator(label: "StorageServiceOperation", keyStore: StorageServiceOperation.keyValueStore, ydbTransaction: ydbTransaction) - ] - - for (label, keyStore) in YDBToGRDBMigration.otherKeyStores { - result.append(GRDBKeyValueStoreMigrator(label: label, keyStore: keyStore, ydbTransaction: ydbTransaction)) - } - - return result - } - - private func profileRecordMigrators(ydbTransaction: YapDatabaseReadTransaction) -> [GRDBMigrator] { - return [ - GRDBUnorderedRecordMigrator(label: "OWSUserProfile", ydbTransaction: ydbTransaction) - ] - } - - private func allUnorderedRecordMigrators(ydbTransaction: YapDatabaseReadTransaction) -> [GRDBMigrator] { - return [ - GRDBUnorderedRecordMigrator(label: "TSAttachment", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "OWSMessageContentJob", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "OWSRecipientIdentity", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "TSThread", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "ExperienceUpgrade", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "StickerPack", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "InstalledSticker", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "KnownStickerPack", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "OWSBackupFragment", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "SignalRecipient", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "OWSDisappearingMessagesConfiguration", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "SignalAccount", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "OWSDevice", ydbTransaction: ydbTransaction), - GRDBUnorderedRecordMigrator(label: "OWSReaction", ydbTransaction: ydbTransaction) - ] - } -} - -// MARK: - - -private class LegacyObjectFinder { - let collection: String - - let transaction: YapDatabaseReadTransaction - - init(collection: String, transaction: YapDatabaseReadTransaction) { - self.collection = collection - self.transaction = transaction - } - - public var count: UInt { - return transaction.numberOfKeys(inCollection: collection) - } - - public func enumerateLegacyKeysAndObjects(block: @escaping (String, T) throws -> Void ) throws { - var knownCollectionKeys = Set() - try transaction.enumerateKeysAndObjects(inCollection: collection) { (collectionKey: String, collectionObj: Any, _: UnsafeMutablePointer) throws -> Void in - guard let legacyObj = collectionObj as? T else { - owsFailDebug("unexpected collectionObj: \(type(of: collectionObj)) collectionKey: \(collectionKey)") - return - } - - // Ignore duplicates in YDB enumerations. - guard !knownCollectionKeys.contains(collectionKey) else { - owsFailDebug("Ignoring duplicate collectionKey: \(collectionKey)") - return - } - knownCollectionKeys.insert(collectionKey) - - try block(collectionKey, legacyObj) - } - } -} - -// MARK: - - -private class LegacyKeyValueFinder: LegacyObjectFinder { - let store: SDSKeyValueStore - - init(store: SDSKeyValueStore, transaction: YapDatabaseReadTransaction) { - self.store = store - super.init(collection: store.collection, transaction: transaction) - } -} - -// MARK: - - -private class LegacyUnorderedFinder: LegacyObjectFinder where RecordType: TSYapDatabaseObject { - init(transaction: YapDatabaseReadTransaction) { - super.init(collection: RecordType.collection(), transaction: transaction) - } -} - -// MARK: - - -private class LegacyInteractionFinder { - let transaction: YapDatabaseReadTransaction - - init(transaction: YapDatabaseReadTransaction) { - self.transaction = transaction - } - - public var count: UInt { - let collection = TSInteraction.collection() - return transaction.numberOfKeys(inCollection: collection) - } - - // We need to enumerate in ascending order of sort id. - public func enumerateLegacyKeysAndObjects(block: @escaping (String, TSInteraction) -> Void ) throws { - guard let view = transaction.safeAutoViewTransaction(TSInteractionsBySortIdDatabaseViewExtensionName) else { - owsFail("Missing interaction view.") - } - var knownUniqueIds = Set() - view.safe_enumerateKeysAndObjects(inGroup: TSInteractionsBySortIdGroup, - extensionName: TSInteractionsBySortIdDatabaseViewExtensionName) { (_, _, object, _, _) in - guard let interaction = object as? TSInteraction else { - owsFailDebug("unexpected interaction: \(type(of: object))") - return - } - - // Ignore duplicates in YDB enumerations. - let uniqueId = interaction.uniqueId - guard !knownUniqueIds.contains(uniqueId) else { - owsFailDebug("Ignoring duplicate uniqueId: \(uniqueId)") - return - } - knownUniqueIds.insert(uniqueId) - - block(uniqueId, interaction) - } - } -} - -// MARK: - - -private class LegacyJobRecordFinder { - - let extensionName = YAPDBJobRecordFinder.dbExtensionName - - var ext: YapDatabaseSecondaryIndexTransaction? - - init(transaction: YapDatabaseReadTransaction) { - self.ext = transaction.safeSecondaryIndexTransaction(extensionName) - } - - public var count: UInt { - guard let ext = ext else { - owsFailDebug("Missing view transcation.") - return 0 - } - var count: UInt = 0 - ext.getNumberOfRows(&count, matching: query) - return count - } - - private var query: YapDatabaseQuery { - let queryFormat = String(format: "ORDER BY %@", "sortId") - return YapDatabaseQuery(string: queryFormat, parameters: []) - } - - public func enumerateJobRecords(block: @escaping (SSKJobRecord) throws -> Void) throws { - try enumerateJobRecords(ext: ext, block: block) - } - - func enumerateJobRecords(ext: YapDatabaseSecondaryIndexTransaction?, block: @escaping (SSKJobRecord) throws -> Void) throws { - guard let ext = ext else { - owsFailDebug("Missing ext.") - return - } - - var errorToRaise: Error? - - ext.enumerateKeysAndObjects(matching: query) { _, _, object, stopPtr in - do { - guard let jobRecord = object as? SSKJobRecord else { - owsFailDebug("expecting jobRecord but found: \(object)") - return - } - try block(jobRecord) - } catch { - owsFailDebug("error: \(error)") - errorToRaise = error - stopPtr.pointee = true - } - } - - if let errorToRaise = errorToRaise { - throw errorToRaise - } - } -} - -// MARK: - - -private class LegacyDecryptJobFinder { - - let ydbTransaction: YapDatabaseReadTransaction - - init(transaction: YapDatabaseReadTransaction) { - ydbTransaction = transaction - } - - var count: UInt { - - let legacyFinder = OWSMessageDecryptJobFinder() - return legacyFinder.queuedJobCount(with: ydbTransaction.asAnyRead) - } - - func enumerateJobRecords(block: @escaping (OWSMessageDecryptJob) throws -> Void) throws { - var errorToRaise: Error? - let legacyFinder = OWSMessageDecryptJobFinder() - try legacyFinder.enumerateJobs(transaction: ydbTransaction.asAnyRead) { (job, stop) in - do { - try block(job) - } catch { - owsFailDebug("error: \(error)") - errorToRaise = error - stop.pointee = true - } - } - - if let errorToRaise = errorToRaise { - throw errorToRaise - } - } -} - -// MARK: - - -@objc -public protocol GRDBMigrator { - var label: String { get } - - var count: UInt { get } - - func migrate(grdbTransaction: GRDBWriteTransaction) throws -} - -extension GRDBMigrator { - func memorySamplerRatio(count: UInt) -> Float { - // Sample no more than N times for a given migration. - let maxSampleCount: Float = 100 - - let count = Float(self.count) - guard count > maxSampleCount else { - return 1 - } - return maxSampleCount / count - } -} - -// MARK: - - -public class GRDBKeyValueStoreMigrator: GRDBMigrator { - public let label: String - private let keyStore: SDSKeyValueStore - private let finder: LegacyKeyValueFinder - - init(label: String, keyStore: SDSKeyValueStore, ydbTransaction: YapDatabaseReadTransaction) { - self.label = "Migrate \(label)" - self.keyStore = keyStore - self.finder = LegacyKeyValueFinder(store: keyStore, transaction: ydbTransaction) - } - - public var count: UInt { - return finder.count - } - - public func migrate(grdbTransaction: GRDBWriteTransaction) throws { - let count = self.count - Logger.info("\(label): \(count)") - try Bench(title: label, memorySamplerRatio: memorySamplerRatio(count: count), logInProduction: true) { memorySampler in - var recordCount = 0 - try finder.enumerateLegacyKeysAndObjects { legacyKey, legacyObject in - recordCount += 1 - if let legacyData = legacyObject as? Data { - self.finder.store.setData(legacyData, key: legacyKey, transaction: grdbTransaction.asAnyWrite) - } else { - self.finder.store.setObject(legacyObject, key: legacyKey, transaction: grdbTransaction.asAnyWrite) - } - memorySampler.sample() - } - Logger.info("Completed with recordCount: \(recordCount)") - } - } -} - -// MARK: - - -public class GRDBUnorderedRecordMigrator: GRDBMigrator where T: SDSModel { - public let label: String - private let finder: LegacyUnorderedFinder - - init(label: String, ydbTransaction: YapDatabaseReadTransaction) { - self.label = "Migrate \(label)" - self.finder = LegacyUnorderedFinder(transaction: ydbTransaction) - } - - public var count: UInt { - return finder.count - } - - public func migrate(grdbTransaction: GRDBWriteTransaction) throws { - let count = self.count - Logger.info("\(label): \(count)") - - var signalRecipientUuids = Set() - var signalRecipientPhoneNumbers = Set() - try Bench(title: label, memorySamplerRatio: memorySamplerRatio(count: count), logInProduction: true) { memorySampler in - var recordCount = 0 - try finder.enumerateLegacyKeysAndObjects { (_, legacyRecord) in - - // SignalRecipients have GRDB uniqueness constraints on the - // phone number and uuid columns. Therefore we need to - // de-duplicate during the migration or migration will fail. - if let signalRecipient = legacyRecord as? SignalRecipient { - if let uuidString = signalRecipient.recipientUUID, - signalRecipientUuids.contains(uuidString) { - // If YDB contains two recipients with the same UUID, discard one. - Logger.warn("Discarding duplicate SignalRecipient: \(uuidString)") - return - } - if let phoneNumber = signalRecipient.recipientPhoneNumber, - signalRecipientPhoneNumbers.contains(phoneNumber) { - // If YDB contains two recipients with the same phone, try to - // discard just the phone number. If the recipient has a uuid, - // we can preserve it. If not, discard the recipient. - if signalRecipient.recipientUUID == nil { - Logger.warn("Discarding duplicate SignalRecipient: \(phoneNumber)") - return - } else { - Logger.warn("Discarding duplicate SignalRecipient phone number: \(phoneNumber)") - signalRecipient.removePhoneNumberForDatabaseMigration() - } - } - if let uuidString = signalRecipient.recipientUUID { - signalRecipientUuids.insert(uuidString) - } - if let phoneNumber = signalRecipient.recipientPhoneNumber { - signalRecipientPhoneNumbers.insert(phoneNumber) - } - } - - recordCount += 1 - legacyRecord.anyInsert(transaction: grdbTransaction.asAnyWrite) - memorySampler.sample() - } - Logger.info("Completed with recordCount: \(recordCount)") - } - } -} - -// MARK: - - -public class GRDBJobRecordMigrator: GRDBMigrator { - public let label: String - private let finder: LegacyJobRecordFinder - - init(ydbTransaction: YapDatabaseReadTransaction) { - self.label = "Migrate SSKJobRecord" - self.finder = LegacyJobRecordFinder(transaction: ydbTransaction) - } - - public var count: UInt { - return finder.count - } - - public func migrate(grdbTransaction: GRDBWriteTransaction) throws { - let count = self.count - Logger.info("\(label): \(count)") - try Bench(title: label, memorySamplerRatio: memorySamplerRatio(count: count), logInProduction: true) { memorySampler in - var recordCount = 0 - try finder.enumerateJobRecords { legacyRecord in - recordCount += 1 - legacyRecord.anyInsert(transaction: grdbTransaction.asAnyWrite) - memorySampler.sample() - } - Logger.info("Completed with recordCount: \(recordCount)") - } - } -} - -// MARK: - - -public class GRDBInteractionMigrator: GRDBMigrator { - public let label: String - private let finder: LegacyInteractionFinder - - init(ydbTransaction: YapDatabaseReadTransaction) { - self.label = "Migrate Interactions" - self.finder = LegacyInteractionFinder(transaction: ydbTransaction) - } - - public var count: UInt { - return finder.count - } - - public func migrate(grdbTransaction: GRDBWriteTransaction) throws { - let count = self.count - Logger.info("\(label): \(count)") - var prevSortId: UInt64? - try Bench(title: label, memorySamplerRatio: memorySamplerRatio(count: count), logInProduction: true) { memorySampler in - var recordCount = 0 - // This must enumerate the interactions in ascending order of sort id. - try finder.enumerateLegacyKeysAndObjects { (_, interaction) in - - // Ensure all interactions have valid, monotonically increasing sort ids. - let minSortId: UInt64 - if let previousSortId = prevSortId { - minSortId = previousSortId + 1 - } else { - minSortId = 1 - } - let sortId: UInt64 - if interaction.sortId >= minSortId { - // Interaction already has valid sort id. - sortId = interaction.sortId - } else { - if interaction.sortId > 0 { - owsFailDebug("Replacing invalid sort id: \(interaction.sortId) -> \(minSortId)") - } else { - owsFailDebug("Setting missing sort id: \(minSortId)") - } - // NOTE: "replaced" sort ids will not be written to YDB. - interaction.replaceSortId(minSortId) - sortId = minSortId - } - prevSortId = sortId - - interaction.anyInsert(transaction: grdbTransaction.asAnyWrite) - recordCount += 1 - memorySampler.sample() - } - Logger.info("Completed with recordCount: \(recordCount)") - } - } -} - -// MARK: - - -public class GRDBDecryptJobMigrator: GRDBMigrator { - public let label: String - private let finder: LegacyDecryptJobFinder - - init(ydbTransaction: YapDatabaseReadTransaction) { - self.label = "Migrate Jobs" - self.finder = LegacyDecryptJobFinder(transaction: ydbTransaction) - } - - public var count: UInt { - return finder.count - } - - public func migrate(grdbTransaction: GRDBWriteTransaction) throws { - let count = self.count - Logger.info("\(label): \(count)") - try Bench(title: label, memorySamplerRatio: memorySamplerRatio(count: count), logInProduction: true) { memorySampler in - var recordCount = 0 - try finder.enumerateJobRecords { legacyJob in - let newJob = SSKMessageDecryptJobRecord( - envelopeData: legacyJob.envelopeData, - serverDeliveryTimestamp: 0, - label: "SSKMessageDecrypt" - ) - newJob.anyInsert(transaction: grdbTransaction.asAnyWrite) - recordCount += 1 - memorySampler.sample() - } - Logger.info("Completed with recordCount: \(recordCount)") - } - } -} diff --git a/SignalMessaging/utils/OWSOrphanDataCleaner.m b/SignalMessaging/utils/OWSOrphanDataCleaner.m index 069c475fc4..adb9ed7b0d 100644 --- a/SignalMessaging/utils/OWSOrphanDataCleaner.m +++ b/SignalMessaging/utils/OWSOrphanDataCleaner.m @@ -13,7 +13,6 @@ #import #import #import -#import #import #import #import @@ -315,10 +314,9 @@ typedef void (^OrphanDataBlock)(OWSOrphanData *); // ever accidentally removing the YDB or GRDB databases during // orphan clean up. NSString *grdbDirectoryPath = [SDSDatabaseStorage grdbDatabaseDirUrl].path; - NSString *ydbDirectoryPath = [OWSPrimaryStorage sharedDataDatabaseDirPath]; NSMutableSet *databaseFilePaths = [NSMutableSet new]; for (NSString *filePath in allOnDiskFilePaths) { - if ([filePath hasPrefix:grdbDirectoryPath] || [filePath hasPrefix:ydbDirectoryPath]) { + if ([filePath hasPrefix:grdbDirectoryPath]) { OWSLogInfo(@"Protecting database file: %@", filePath); [databaseFilePaths addObject:filePath]; } @@ -326,8 +324,6 @@ typedef void (^OrphanDataBlock)(OWSOrphanData *); [allOnDiskFilePaths minusSet:databaseFilePaths]; OWSLogVerbose( @"grdbDirectoryPath: %@ (%d)", grdbDirectoryPath, [OWSFileSystem fileOrFolderExistsAtPath:grdbDirectoryPath]); - OWSLogVerbose( - @"ydbDirectoryPath: %@ (%d)", ydbDirectoryPath, [OWSFileSystem fileOrFolderExistsAtPath:ydbDirectoryPath]); OWSLogVerbose(@"databaseFilePaths: %lu", (unsigned long)databaseFilePaths.count); OWSLogVerbose(@"allOnDiskFilePaths: %lu", (unsigned long)allOnDiskFilePaths.count); diff --git a/SignalMessaging/utils/OWSPreferences.h b/SignalMessaging/utils/OWSPreferences.h index 8c893bc9ce..378eaea6a5 100644 --- a/SignalMessaging/utils/OWSPreferences.h +++ b/SignalMessaging/utils/OWSPreferences.h @@ -23,7 +23,6 @@ extern NSString *const OWSPreferencesCallLoggingDidChangeNotification; @class SDSAnyReadTransaction; @class SDSAnyWriteTransaction; @class SDSKeyValueStore; -@class YapDatabaseReadWriteTransaction; @interface OWSPreferences : NSObject @@ -37,9 +36,6 @@ extern NSString *const OWSPreferencesCallLoggingDidChangeNotification; + (BOOL)isReadyForAppExtensions; -+ (BOOL)isYdbReadyForAppExtensions; -+ (void)setIsYdbReadyForAppExtensions; - + (BOOL)isGrdbReadyForAppExtensions; + (void)setIsGrdbReadyForAppExtensions; @@ -99,10 +95,6 @@ extern NSString *const OWSPreferencesCallLoggingDidChangeNotification; - (BOOL)isSystemCallLogEnabled; - (void)setIsSystemCallLogEnabled:(BOOL)value; -#pragma mark - Legacy CallKit settings - -- (void)applyCallLoggingSettingsForLegacyUsersWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; - #pragma mark direct call connectivity (non-TURN) - (BOOL)doCallsHideIPAddress; diff --git a/SignalMessaging/utils/OWSPreferences.m b/SignalMessaging/utils/OWSPreferences.m index 94c81d3f14..699ea9d9cf 100644 --- a/SignalMessaging/utils/OWSPreferences.m +++ b/SignalMessaging/utils/OWSPreferences.m @@ -10,7 +10,6 @@ #import #import #import -#import NS_ASSUME_NONNULL_BEGIN @@ -44,7 +43,6 @@ NSString *const OWSPreferencesKeyShouldShowUnidentifiedDeliveryIndicators = @"OWSPreferencesKeyShouldShowUnidentifiedDeliveryIndicators"; NSString *const OWSPreferencesKeyShouldNotifyOfNewAccountKey = @"OWSPreferencesKeyShouldNotifyOfNewAccountKey"; NSString *const OWSPreferencesKeyIOSUpgradeNagDate = @"iOSUpgradeNagDate"; -NSString *const OWSPreferencesKey_IsYdbReadyForAppExtensions = @"isReadyForAppExtensions_5"; NSString *const OWSPreferencesKey_IsGrdbReadyForAppExtensions = @"IsGrdbReadyForAppExtensions"; NSString *const OWSPreferencesKey_IsAudibleErrorLoggingEnabled = @"IsAudibleErrorLoggingEnabled"; NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySystemCallLogEnabled"; @@ -174,20 +172,8 @@ NSString *const OWSPreferencesKeyWasGroupCallTooltipShownCount = @"OWSPreference + (BOOL)isReadyForAppExtensions { - if (StorageCoordinator.dataStoreForUI == DataStoreGrdb && !self.isGrdbReadyForAppExtensions) { - return NO; - } - return self.isYdbReadyForAppExtensions; -} - -+ (BOOL)isYdbReadyForAppExtensions -{ - return [self appUserDefaultsFlagWithKey:OWSPreferencesKey_IsYdbReadyForAppExtensions]; -} - -+ (void)setIsYdbReadyForAppExtensions -{ - [self setAppUserDefaultsFlagWithKey:OWSPreferencesKey_IsYdbReadyForAppExtensions]; + OWSAssertDebug(StorageCoordinator.dataStoreForUI == DataStoreGrdb); + return self.isGrdbReadyForAppExtensions; } + (BOOL)isGrdbReadyForAppExtensions @@ -352,52 +338,6 @@ NSString *const OWSPreferencesKeyWasGroupCallTooltipShownCount = @"OWSPreference [self setBool:value forKey:OWSPreferencesKeySystemCallLogEnabled]; } -// In iOS 10.2.1, Apple fixed a bug wherein call history was backed up to iCloud. -// -// See: https://support.apple.com/en-us/HT207482 -// -// In iOS 11, Apple introduced a property CXProviderConfiguration.includesCallsInRecents -// that allows us to prevent Signal calls made with CallKit from showing up in the device's -// call history. -// -// Therefore in versions of iOS after 11, we have no need of call privacy. -#pragma mark Legacy CallKit - -// Be a little conservative with system call logging with legacy users, even though it's -// not synced to iCloud, users could be concerned to suddenly see caller names in their -// recent calls list. -- (void)applyCallLoggingSettingsForLegacyUsersWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - BOOL wasUsingCallKit = - [self.keyValueStore getBool:OWSPreferencesKeyCallKitEnabled defaultValue:YES transaction:transaction.asAnyRead]; - BOOL wasUsingCallKitPrivacy = [self.keyValueStore getBool:OWSPreferencesKeyCallKitPrivacyEnabled - defaultValue:YES - transaction:transaction.asAnyRead]; - - BOOL shouldLogCallsInRecents = ^{ - if (wasUsingCallKit && !wasUsingCallKitPrivacy) { - // User was using CallKit and explicitly opted in to showing names/numbers, - // so it's OK to continue to show names/numbers in the system recents list. - return YES; - } else { - // User was not previously showing names/numbers in the system - // recents list, so don't opt them in. - return NO; - } - }(); - - OWSLogInfo(@"Migrating setting - System Call Log Enabled: %d", shouldLogCallsInRecents); - - [self.keyValueStore setBool:shouldLogCallsInRecents - key:OWSPreferencesKeySystemCallLogEnabled - transaction:transaction.asAnyWrite]; - - // We need to reload the callService.callUIAdapter here, but SignalMessaging doesn't know about CallService, so we use - // notifications to decouple the code. This is admittedly awkward, but it only happens once, and the alternative would - // be importing all the call related classes into SignalMessaging. - [[NSNotificationCenter defaultCenter] postNotificationNameAsync:OWSPreferencesCallLoggingDidChangeNotification object:nil]; -} - - (BOOL)wasViewOnceTooltipShown { return [self boolForKey:OWSPreferencesKeyWasViewOnceTooltipShown defaultValue:NO]; diff --git a/SignalMessaging/utils/ThreadUtil.h b/SignalMessaging/utils/ThreadUtil.h index b4f454a43f..490626d2e7 100644 --- a/SignalMessaging/utils/ThreadUtil.h +++ b/SignalMessaging/utils/ThreadUtil.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // NS_ASSUME_NONNULL_BEGIN @@ -20,7 +20,6 @@ NS_ASSUME_NONNULL_BEGIN @class TSInteraction; @class TSOutgoingMessage; @class TSThread; -@class YapDatabaseReadTransaction; #pragma mark - diff --git a/SignalServiceKit.podspec b/SignalServiceKit.podspec index c0ef33d9fa..4335da3905 100644 --- a/SignalServiceKit.podspec +++ b/SignalServiceKit.podspec @@ -44,7 +44,6 @@ An Objective-C library for communicating with the Signal messaging service. s.dependency 'CocoaLumberjack' s.dependency 'AFNetworking/NSURLSession' s.dependency 'Mantle' - s.dependency 'YapDatabase/SQLCipher' s.dependency 'Starscream' s.dependency 'libPhoneNumber-iOS' s.dependency 'GRKOpenSSLFramework' diff --git a/SignalServiceKit/src/Account/TSAccountManager.m b/SignalServiceKit/src/Account/TSAccountManager.m index 8f2bc8cbde..71878ea6c0 100644 --- a/SignalServiceKit/src/Account/TSAccountManager.m +++ b/SignalServiceKit/src/Account/TSAccountManager.m @@ -381,6 +381,9 @@ NSString *NSStringForOWSRegistrationState(OWSRegistrationState value) [self storeLocalNumber:phoneNumber uuid:uuid transaction:transaction]; }); + // Clear this flag so we don't show the "dropped ydb" ui during future re-registrations. + [SSKPreferences setDidDropYdb:NO]; + [self postRegistrationStateDidChangeNotification]; } @@ -978,8 +981,7 @@ NSString *NSStringForOWSRegistrationState(OWSRegistrationState value) - (void)registerForTestsWithLocalNumber:(NSString *)localNumber uuid:(NSUUID *)uuid { - OWSAssertDebug( - SSKFeatureFlags.storageMode == StorageModeYdbTests || SSKFeatureFlags.storageMode == StorageModeGrdbTests); + OWSAssertDebug(SSKFeatureFlags.storageMode == StorageModeGrdbTests); OWSAssertDebug(CurrentAppContext().isRunningTests); OWSAssertDebug(localNumber.length > 0); OWSAssertDebug(uuid != nil); diff --git a/SignalServiceKit/src/Contacts/AnyThreadFinder.swift b/SignalServiceKit/src/Contacts/AnyThreadFinder.swift index ba508bdfa9..9f0bb3e668 100644 --- a/SignalServiceKit/src/Contacts/AnyThreadFinder.swift +++ b/SignalServiceKit/src/Contacts/AnyThreadFinder.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // import Foundation @@ -7,7 +7,6 @@ import Foundation @objc public class AnyContactThreadFinder: NSObject { let grdbAdapter = GRDBContactThreadFinder() - let yapdbAdapter = YAPDBSignalServiceAddressIndex() } // MARK: - @@ -18,8 +17,6 @@ public extension AnyContactThreadFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.contactThread(for: address, transaction: transaction) - case .yapRead(let transaction): - return yapdbAdapter.fetchOne(for: address, transaction: transaction) } } @@ -28,8 +25,6 @@ public extension AnyContactThreadFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.contactThreadForUUID(uuid, transaction: transaction) - case .yapRead(let transaction): - return yapdbAdapter.fetchOneForUUID(uuid, transaction: transaction) } } @@ -38,8 +33,6 @@ public extension AnyContactThreadFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.contactThreadForPhoneNumber(phoneNumber, transaction: transaction) - case .yapRead(let transaction): - return yapdbAdapter.fetchOneForPhoneNumber(phoneNumber, transaction: transaction) } } } diff --git a/SignalServiceKit/src/Contacts/OWSDisappearingMessagesConfiguration+SDS.swift b/SignalServiceKit/src/Contacts/OWSDisappearingMessagesConfiguration+SDS.swift index d9048f2a21..0d7cf757f2 100644 --- a/SignalServiceKit/src/Contacts/OWSDisappearingMessagesConfiguration+SDS.swift +++ b/SignalServiceKit/src/Contacts/OWSDisappearingMessagesConfiguration+SDS.swift @@ -356,8 +356,6 @@ public extension OWSDisappearingMessagesConfiguration { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return OWSDisappearingMessagesConfiguration.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(DisappearingMessagesConfigurationRecord.databaseTableName) WHERE \(disappearingMessagesConfigurationColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -388,14 +386,6 @@ public extension OWSDisappearingMessagesConfiguration { batchSize: UInt, block: @escaping (OWSDisappearingMessagesConfiguration, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - OWSDisappearingMessagesConfiguration.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? OWSDisappearingMessagesConfiguration else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = OWSDisappearingMessagesConfiguration.grdbFetchCursor(transaction: grdbTransaction) @@ -437,10 +427,6 @@ public extension OWSDisappearingMessagesConfiguration { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: OWSDisappearingMessagesConfiguration.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -472,8 +458,6 @@ public extension OWSDisappearingMessagesConfiguration { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: OWSDisappearingMessagesConfiguration.collection()) case .grdbRead(let grdbTransaction): return DisappearingMessagesConfigurationRecord.ows_fetchCount(grdbTransaction.database) } @@ -483,8 +467,6 @@ public extension OWSDisappearingMessagesConfiguration { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: OWSDisappearingMessagesConfiguration.collection()) case .grdbWrite(let grdbTransaction): do { try DisappearingMessagesConfigurationRecord.deleteAll(grdbTransaction.database) @@ -533,8 +515,6 @@ public extension OWSDisappearingMessagesConfiguration { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: OWSDisappearingMessagesConfiguration.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(DisappearingMessagesConfigurationRecord.databaseTableName) WHERE \(disappearingMessagesConfigurationColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Contacts/SignalAccount+SDS.swift b/SignalServiceKit/src/Contacts/SignalAccount+SDS.swift index 5c30e2b8bb..2d91eb4e9e 100644 --- a/SignalServiceKit/src/Contacts/SignalAccount+SDS.swift +++ b/SignalServiceKit/src/Contacts/SignalAccount+SDS.swift @@ -407,8 +407,6 @@ public extension SignalAccount { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return SignalAccount.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(SignalAccountRecord.databaseTableName) WHERE \(signalAccountColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -439,14 +437,6 @@ public extension SignalAccount { batchSize: UInt, block: @escaping (SignalAccount, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - SignalAccount.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? SignalAccount else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = SignalAccount.grdbFetchCursor(transaction: grdbTransaction) @@ -488,10 +478,6 @@ public extension SignalAccount { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: SignalAccount.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -523,8 +509,6 @@ public extension SignalAccount { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: SignalAccount.collection()) case .grdbRead(let grdbTransaction): return SignalAccountRecord.ows_fetchCount(grdbTransaction.database) } @@ -534,8 +518,6 @@ public extension SignalAccount { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: SignalAccount.collection()) case .grdbWrite(let grdbTransaction): do { try SignalAccountRecord.deleteAll(grdbTransaction.database) @@ -584,8 +566,6 @@ public extension SignalAccount { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: SignalAccount.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(SignalAccountRecord.databaseTableName) WHERE \(signalAccountColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Contacts/SignalAccountFinder.swift b/SignalServiceKit/src/Contacts/SignalAccountFinder.swift index a1a270f855..6db04d876e 100644 --- a/SignalServiceKit/src/Contacts/SignalAccountFinder.swift +++ b/SignalServiceKit/src/Contacts/SignalAccountFinder.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // import Foundation @@ -7,7 +7,6 @@ import Foundation @objc public class AnySignalAccountFinder: NSObject { let grdbAdapter = GRDBSignalAccountFinder() - let yapdbAdapter = YAPDBSignalServiceAddressIndex() } extension AnySignalAccountFinder { @@ -16,8 +15,6 @@ extension AnySignalAccountFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.signalAccount(for: address, transaction: transaction) - case .yapRead(let transaction): - return yapdbAdapter.fetchOne(for: address, transaction: transaction) } } } diff --git a/SignalServiceKit/src/Contacts/SignalRecipient+SDS.swift b/SignalServiceKit/src/Contacts/SignalRecipient+SDS.swift index 0a5149c616..3434d742b1 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient+SDS.swift +++ b/SignalServiceKit/src/Contacts/SignalRecipient+SDS.swift @@ -370,8 +370,6 @@ public extension SignalRecipient { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return SignalRecipient.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(SignalRecipientRecord.databaseTableName) WHERE \(signalRecipientColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -402,14 +400,6 @@ public extension SignalRecipient { batchSize: UInt, block: @escaping (SignalRecipient, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - SignalRecipient.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? SignalRecipient else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = SignalRecipient.grdbFetchCursor(transaction: grdbTransaction) @@ -451,10 +441,6 @@ public extension SignalRecipient { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: SignalRecipient.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -486,8 +472,6 @@ public extension SignalRecipient { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: SignalRecipient.collection()) case .grdbRead(let grdbTransaction): return SignalRecipientRecord.ows_fetchCount(grdbTransaction.database) } @@ -497,8 +481,6 @@ public extension SignalRecipient { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: SignalRecipient.collection()) case .grdbWrite(let grdbTransaction): do { try SignalRecipientRecord.deleteAll(grdbTransaction.database) @@ -547,8 +529,6 @@ public extension SignalRecipient { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: SignalRecipient.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(SignalRecipientRecord.databaseTableName) WHERE \(signalRecipientColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Contacts/SignalRecipientFinder.swift b/SignalServiceKit/src/Contacts/SignalRecipientFinder.swift index 349ec73933..b08ddb0509 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipientFinder.swift +++ b/SignalServiceKit/src/Contacts/SignalRecipientFinder.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // import Foundation @@ -7,7 +7,6 @@ import Foundation @objc public class AnySignalRecipientFinder: NSObject { let grdbAdapter = GRDBSignalRecipientFinder() - let yapdbAdapter = YAPDBSignalServiceAddressIndex() } extension AnySignalRecipientFinder { @@ -16,8 +15,6 @@ extension AnySignalRecipientFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.signalRecipientForUUID(uuid, transaction: transaction) - case .yapRead(let transaction): - return yapdbAdapter.fetchOneForUUID(uuid, transaction: transaction) } } @@ -26,8 +23,6 @@ extension AnySignalRecipientFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.signalRecipientForPhoneNumber(phoneNumber, transaction: transaction) - case .yapRead(let transaction): - return yapdbAdapter.fetchOneForPhoneNumber(phoneNumber, transaction: transaction) } } @@ -36,8 +31,6 @@ extension AnySignalRecipientFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.signalRecipient(for: address, transaction: transaction) - case .yapRead(let transaction): - return yapdbAdapter.fetchOne(for: address, transaction: transaction) } } @@ -45,8 +38,6 @@ extension AnySignalRecipientFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.signalRecipients(for: addresses, transaction: transaction) - case .yapRead: - fatalError("yap not supported") } } @@ -58,8 +49,6 @@ extension AnySignalRecipientFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.registeredRecipientsWithoutUUID(transaction: transaction) - case .yapRead: - fatalError("yap not supported") } } } diff --git a/SignalServiceKit/src/Contacts/TSThread+SDS.swift b/SignalServiceKit/src/Contacts/TSThread+SDS.swift index 6326b75442..df348efff4 100644 --- a/SignalServiceKit/src/Contacts/TSThread+SDS.swift +++ b/SignalServiceKit/src/Contacts/TSThread+SDS.swift @@ -678,8 +678,6 @@ public extension TSThread { } switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return TSThread.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(ThreadRecord.databaseTableName) WHERE \(threadColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -710,14 +708,6 @@ public extension TSThread { batchSize: UInt, block: @escaping (TSThread, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - TSThread.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? TSThread else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = TSThread.grdbFetchCursor(transaction: grdbTransaction) @@ -759,10 +749,6 @@ public extension TSThread { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: TSThread.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -794,8 +780,6 @@ public extension TSThread { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: TSThread.collection()) case .grdbRead(let grdbTransaction): return ThreadRecord.ows_fetchCount(grdbTransaction.database) } @@ -805,8 +789,6 @@ public extension TSThread { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: TSThread.collection()) case .grdbWrite(let grdbTransaction): do { try ThreadRecord.deleteAll(grdbTransaction.database) @@ -855,8 +837,6 @@ public extension TSThread { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: TSThread.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(ThreadRecord.databaseTableName) WHERE \(threadColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Contacts/TSThread.m b/SignalServiceKit/src/Contacts/TSThread.m index 6ad70fcaa2..d4565b9bfb 100644 --- a/SignalServiceKit/src/Contacts/TSThread.m +++ b/SignalServiceKit/src/Contacts/TSThread.m @@ -462,16 +462,12 @@ lastVisibleSortIdOnScreenPercentageObsolete:(double)lastVisibleSortIdOnScreenPer - (int64_t)messageSortIdForMessage:(TSInteraction *)message transaction:(SDSAnyWriteTransaction *)transaction { - if (transaction.transitional_yapWriteTransaction) { - return message.sortId; + if (message.grdbId == nil) { + OWSFailDebug(@"Missing messageSortId."); + } else if (message.grdbId.unsignedLongLongValue == 0) { + OWSFailDebug(@"Invalid messageSortId."); } else { - if (message.grdbId == nil) { - OWSFailDebug(@"Missing messageSortId."); - } else if (message.grdbId.unsignedLongLongValue == 0) { - OWSFailDebug(@"Invalid messageSortId."); - } else { - return message.grdbId.longLongValue; - } + return message.grdbId.longLongValue; } return 0; } diff --git a/SignalServiceKit/src/Contacts/YAPDBSignalServiceAddressExtension.swift b/SignalServiceKit/src/Contacts/YAPDBSignalServiceAddressExtension.swift deleted file mode 100644 index 702339d61c..0000000000 --- a/SignalServiceKit/src/Contacts/YAPDBSignalServiceAddressExtension.swift +++ /dev/null @@ -1,156 +0,0 @@ -// -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. -// - -import Foundation - -protocol YAPDBSignalServiceAddressIndexable: class { - var indexableUUIDValue: String? { get } - var indexablePhoneNumberValue: String? { get } -} - -extension SignalAccount: YAPDBSignalServiceAddressIndexable { - var indexableUUIDValue: String? { return recipientUUID } - var indexablePhoneNumberValue: String? { return recipientPhoneNumber } -} - -extension SignalRecipient: YAPDBSignalServiceAddressIndexable { - var indexableUUIDValue: String? { return recipientUUID } - var indexablePhoneNumberValue: String? { return recipientPhoneNumber } -} - -extension TSContactThread: YAPDBSignalServiceAddressIndexable { - var indexableUUIDValue: String? { return contactUUID } - var indexablePhoneNumberValue: String? { return contactPhoneNumber } -} - -extension OWSUserProfile: YAPDBSignalServiceAddressIndexable { - var indexableUUIDValue: String? { return recipientUUID } - var indexablePhoneNumberValue: String? { return recipientPhoneNumber } -} - -@objc -class YAPDBSignalServiceAddressIndex: NSObject { - private static let indexableTypes: [YAPDBSignalServiceAddressIndexable.Type] = [ - SignalAccount.self, - SignalRecipient.self, - TSContactThread.self - ] - - private static let uuidKey = "uuidKey" - private static let phoneNumberKey = "phoneNumberKey" - private static let classNameKey = "classNameKey" - - private static let phoneNumberIndexName = "index_on_recipientPhoneNumber" - private static let uuidIndexName = "index_on_recipientUUID" - - func fetchOne(for address: SignalServiceAddress, transaction: YapDatabaseReadTransaction) -> T? { - if let result: T = fetchOneForUUID(address.uuid, transaction: transaction) { - return result - } else if let result: T = fetchOneForPhoneNumber(address.phoneNumber, transaction: transaction) { - return result - } else { - return nil - } - } - - func fetchOneForUUID(_ uuid: UUID?, transaction: YapDatabaseReadTransaction) -> T? { - guard let uuidString = uuid?.uuidString else { return nil } - - guard let ext = transaction.ext(YAPDBSignalServiceAddressIndex.uuidIndexName) as? YapDatabaseSecondaryIndexTransaction else { - owsFailDebug("Unexpected transaction type for extension") - return nil - } - - let queryFormat = String( - format: "WHERE %@ = \"%@\" AND %@ = \"%@\"", - YAPDBSignalServiceAddressIndex.uuidKey, - uuidString, - YAPDBSignalServiceAddressIndex.classNameKey, - NSStringFromClass(T.self) - ) - let query = YapDatabaseQuery(string: queryFormat, parameters: []) - - var matchedAccount: T? - - ext.enumerateKeysAndObjects(matching: query) { _, _, object, stop in - guard let account = object as? T else { - return - } - matchedAccount = account - stop.pointee = true - } - - return matchedAccount - } - - func fetchOneForPhoneNumber(_ phoneNumber: String?, transaction: YapDatabaseReadTransaction) -> T? { - guard let phoneNumber = phoneNumber else { return nil } - - guard let ext = transaction.ext(YAPDBSignalServiceAddressIndex.phoneNumberIndexName) as? YapDatabaseSecondaryIndexTransaction else { - owsFailDebug("Unexpected transaction type for extension") - return nil - } - - let queryFormat = String( - format: "WHERE %@ = \"%@\" AND %@ = \"%@\"", - YAPDBSignalServiceAddressIndex.phoneNumberKey, - phoneNumber, - YAPDBSignalServiceAddressIndex.classNameKey, - NSStringFromClass(T.self) - ) - let query = YapDatabaseQuery(string: queryFormat, parameters: []) - - var matchedAccount: T? - - ext.enumerateKeysAndObjects(matching: query) { _, _, object, stop in - guard let account = object as? T else { - return - } - matchedAccount = account - stop.pointee = true - } - - return matchedAccount - } - - @objc - static func asyncRegisterDatabaseExtensions(_ storage: OWSStorage) { - storage.asyncRegister(indexUUIDExtension(), withName: uuidIndexName) - storage.asyncRegister(indexPhoneNumberExtension(), withName: phoneNumberIndexName) - } - - private static func indexUUIDExtension() -> YapDatabaseSecondaryIndex { - let setup = YapDatabaseSecondaryIndexSetup() - setup.addColumn(uuidKey, with: .text) - setup.addColumn(classNameKey, with: .text) - - let handler = YapDatabaseSecondaryIndexHandler.withObjectBlock { _, dict, _, _, object in - guard let indexableObject = object as? YAPDBSignalServiceAddressIndexable else { - return - } - - dict[uuidKey] = indexableObject.indexableUUIDValue - dict[classNameKey] = NSStringFromClass(type(of: indexableObject)) - } - - return YapDatabaseSecondaryIndex(setup: setup, handler: handler, versionTag: "2") - } - - private static func indexPhoneNumberExtension() -> YapDatabaseSecondaryIndex { - let setup = YapDatabaseSecondaryIndexSetup() - setup.addColumn(phoneNumberKey, with: .text) - setup.addColumn(classNameKey, with: .text) - - let handler = YapDatabaseSecondaryIndexHandler.withObjectBlock { _, dict, _, _, object in - guard let indexableObject = object as? YAPDBSignalServiceAddressIndexable else { - return - } - - dict[phoneNumberKey] = indexableObject.indexablePhoneNumberValue - dict[classNameKey] = NSStringFromClass(type(of: indexableObject)) - } - - return YapDatabaseSecondaryIndex(setup: setup, handler: handler, versionTag: "2") - } -} diff --git a/SignalServiceKit/src/Devices/OWSDevice+SDS.swift b/SignalServiceKit/src/Devices/OWSDevice+SDS.swift index c105ab40ef..5a03eccd6e 100644 --- a/SignalServiceKit/src/Devices/OWSDevice+SDS.swift +++ b/SignalServiceKit/src/Devices/OWSDevice+SDS.swift @@ -376,8 +376,6 @@ public extension OWSDevice { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return OWSDevice.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(DeviceRecord.databaseTableName) WHERE \(deviceColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -408,14 +406,6 @@ public extension OWSDevice { batchSize: UInt, block: @escaping (OWSDevice, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - OWSDevice.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? OWSDevice else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = OWSDevice.grdbFetchCursor(transaction: grdbTransaction) @@ -457,10 +447,6 @@ public extension OWSDevice { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: OWSDevice.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -492,8 +478,6 @@ public extension OWSDevice { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: OWSDevice.collection()) case .grdbRead(let grdbTransaction): return DeviceRecord.ows_fetchCount(grdbTransaction.database) } @@ -503,8 +487,6 @@ public extension OWSDevice { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: OWSDevice.collection()) case .grdbWrite(let grdbTransaction): do { try DeviceRecord.deleteAll(grdbTransaction.database) @@ -553,8 +535,6 @@ public extension OWSDevice { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: OWSDevice.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(DeviceRecord.databaseTableName) WHERE \(deviceColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachment+SDS.swift b/SignalServiceKit/src/Messages/Attachments/TSAttachment+SDS.swift index 7abf535011..97d2784db4 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachment+SDS.swift +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachment+SDS.swift @@ -732,8 +732,6 @@ public extension TSAttachment { } switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return TSAttachment.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(AttachmentRecord.databaseTableName) WHERE \(attachmentColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -764,14 +762,6 @@ public extension TSAttachment { batchSize: UInt, block: @escaping (TSAttachment, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - TSAttachment.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? TSAttachment else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = TSAttachment.grdbFetchCursor(transaction: grdbTransaction) @@ -813,10 +803,6 @@ public extension TSAttachment { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: TSAttachment.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -848,8 +834,6 @@ public extension TSAttachment { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: TSAttachment.collection()) case .grdbRead(let grdbTransaction): return AttachmentRecord.ows_fetchCount(grdbTransaction.database) } @@ -859,8 +843,6 @@ public extension TSAttachment { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: TSAttachment.collection()) case .grdbWrite(let grdbTransaction): do { try AttachmentRecord.deleteAll(grdbTransaction.database) @@ -909,8 +891,6 @@ public extension TSAttachment { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: TSAttachment.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(AttachmentRecord.databaseTableName) WHERE \(attachmentColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m index 7e925eebfa..aa57066b97 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m @@ -350,13 +350,6 @@ NSString *NSStringForTSAttachmentPointerState(TSAttachmentPointerState value) }]; } -- (void)ydb_saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - [self checkForStreamOverwrite:transaction.asAnyRead]; - - [super ydb_saveWithTransaction:transaction]; -} - - (void)anyWillInsertWithTransaction:(SDSAnyWriteTransaction *)transaction { [super anyWillInsertWithTransaction:transaction]; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m index bea9e27eed..c588a87738 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m @@ -506,7 +506,7 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); - (BOOL)canAsyncUpdate { - return (!CurrentAppContext().isRunningTests && !self.storageCoordinator.isMigrating); + return !CurrentAppContext().isRunningTests; } - (BOOL)isValidVideo diff --git a/SignalServiceKit/src/Messages/Interactions/TSIncomingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSIncomingMessage.m index 06a15a4287..953ff224f1 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSIncomingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSIncomingMessage.m @@ -9,7 +9,6 @@ #import "OWSReadReceiptManager.h" #import "TSAttachmentPointer.h" #import "TSContactThread.h" -#import "TSDatabaseSecondaryIndexes.h" #import "TSGroupThread.h" #import #import diff --git a/SignalServiceKit/src/Messages/Interactions/TSInteraction+SDS.swift b/SignalServiceKit/src/Messages/Interactions/TSInteraction+SDS.swift index 21f9903943..b8191317a0 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSInteraction+SDS.swift +++ b/SignalServiceKit/src/Messages/Interactions/TSInteraction+SDS.swift @@ -3635,8 +3635,6 @@ public extension TSInteraction { } switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return TSInteraction.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(InteractionRecord.databaseTableName) WHERE \(interactionColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -3667,14 +3665,6 @@ public extension TSInteraction { batchSize: UInt, block: @escaping (TSInteraction, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - TSInteraction.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? TSInteraction else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = TSInteraction.grdbFetchCursor(transaction: grdbTransaction) @@ -3716,10 +3706,6 @@ public extension TSInteraction { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: TSInteraction.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -3751,8 +3737,6 @@ public extension TSInteraction { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: TSInteraction.collection()) case .grdbRead(let grdbTransaction): return InteractionRecord.ows_fetchCount(grdbTransaction.database) } @@ -3762,8 +3746,6 @@ public extension TSInteraction { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: TSInteraction.collection()) case .grdbWrite(let grdbTransaction): do { try InteractionRecord.deleteAll(grdbTransaction.database) @@ -3812,8 +3794,6 @@ public extension TSInteraction { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: TSInteraction.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(InteractionRecord.databaseTableName) WHERE \(interactionColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Messages/Interactions/TSInteraction.h b/SignalServiceKit/src/Messages/Interactions/TSInteraction.h index c4a6d1fb48..bcf72022ae 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSInteraction.h +++ b/SignalServiceKit/src/Messages/Interactions/TSInteraction.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // #import "BaseModel.h" @@ -92,17 +92,6 @@ NS_DESIGNATED_INITIALIZER NS_SWIFT_NAME(init(grdbId:uniqueId:receivedAtTimestamp #pragma mark Utility Method -// POST GRDB TODO: Remove this method. -+ (NSArray *)ydb_interactionsWithTimestamp:(uint64_t)timestamp - ofClass:(Class)clazz - withTransaction:(YapDatabaseReadTransaction *)transaction; - - -// POST GRDB TODO: Remove this method. -+ (NSArray *)ydb_interactionsWithTimestamp:(uint64_t)timestamp - filter:(BOOL (^_Nonnull)(TSInteraction *))filter - withTransaction:(YapDatabaseReadTransaction *)transaction; - - (uint64_t)timestampForLegacySorting; - (NSComparisonResult)compareForSorting:(TSInteraction *)other; @@ -114,11 +103,6 @@ NS_DESIGNATED_INITIALIZER NS_SWIFT_NAME(init(grdbId:uniqueId:receivedAtTimestamp // unseen message indicators, etc. - (BOOL)isDynamicInteraction; -// NOTE: This is only for use by a legacy migration. -- (void)ydb_saveNextSortIdWithTransaction:(YapDatabaseReadWriteTransaction *)transaction - NS_SWIFT_NAME(ydb_saveNextSortId(transaction:)); - -// NOTE: This is only for use by the YDB-to-GRDB legacy migration. - (void)replaceSortId:(uint64_t)sortId; #if TESTABLE_BUILD diff --git a/SignalServiceKit/src/Messages/Interactions/TSInteraction.m b/SignalServiceKit/src/Messages/Interactions/TSInteraction.m index 6d1bc0599e..00e1c8b18f 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSInteraction.m +++ b/SignalServiceKit/src/Messages/Interactions/TSInteraction.m @@ -3,7 +3,6 @@ // #import "TSInteraction.h" -#import "TSDatabaseSecondaryIndexes.h" #import "TSThread.h" #import #import @@ -54,43 +53,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) return YES; } -+ (NSArray *)ydb_interactionsWithTimestamp:(uint64_t)timestamp - ofClass:(Class)clazz - withTransaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(timestamp > 0); - - // Accept any interaction. - return [self ydb_interactionsWithTimestamp:timestamp - filter:^(TSInteraction *interaction) { - return [interaction isKindOfClass:clazz]; - } - withTransaction:transaction]; -} - -+ (NSArray *)ydb_interactionsWithTimestamp:(uint64_t)timestamp - filter:(BOOL (^_Nonnull)(TSInteraction *))filter - withTransaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(timestamp > 0); - - NSMutableArray *interactions = [NSMutableArray new]; - - [TSDatabaseSecondaryIndexes enumerateMessagesWithTimestamp:timestamp - withBlock:^(NSString *collection, NSString *key, BOOL *stop) { - TSInteraction *interaction = - [TSInteraction anyFetchWithUniqueId:key - transaction:transaction.asAnyRead]; - if (!filter(interaction)) { - return; - } - [interactions addObject:interaction]; - } - usingTransaction:transaction]; - - return [interactions copy]; -} - + (NSString *)collection { return @"TSInteraction"; } @@ -298,29 +260,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) #pragma mark - Any Transaction Hooks -- (void)anyWillInsertWithTransaction:(SDSAnyWriteTransaction *)transaction -{ - [super anyWillInsertWithTransaction:transaction]; - - if (transaction.transitional_yapWriteTransaction != nil) { - [self ensureIdsWithTransaction:transaction.transitional_yapWriteTransaction]; - } -} - -- (void)ensureIdsWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(transaction); - - if (self.uniqueId.length < 1) { - OWSFailDebug(@"Missing uniqueId."); - return; - } - - if (self.sortId == 0) { - self.sortId = [SSKIncrementingIdFinder nextIdWithKey:[TSInteraction collection] transaction:transaction]; - } -} - - (void)anyDidInsertWithTransaction:(SDSAnyWriteTransaction *)transaction { [super anyDidInsertWithTransaction:transaction]; @@ -370,19 +309,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) #pragma mark - sorting migration -- (void)ydb_saveNextSortIdWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (self.sortId != 0) { - // This could happen if something else in our startup process saved the interaction - // e.g. another migration ran. - // During the migration, since we're enumerating the interactions in the proper order, - // we want to ignore any previously assigned sortId - self.sortId = 0; - } - [self ydb_saveWithTransaction:transaction]; -} - -// NOTE: This is only for use by the YDB-to-GRDB legacy migration. - (void)replaceSortId:(uint64_t)sortId { _sortId = sortId; } diff --git a/SignalServiceKit/src/Messages/Interactions/TSInteraction.swift b/SignalServiceKit/src/Messages/Interactions/TSInteraction.swift index 4f5f8cea41..e5ae44ed02 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSInteraction.swift +++ b/SignalServiceKit/src/Messages/Interactions/TSInteraction.swift @@ -10,9 +10,6 @@ extension TSInteraction { @objc public func fillInMissingSortIdForJustInsertedInteraction(transaction: SDSAnyReadTransaction) { switch transaction.readTransaction { - case .yapRead: - owsFailDebug("Unexpected transaction.") - return case .grdbRead(let grdbRead): fillInMissingSortIdForJustInsertedInteraction(transaction: grdbRead) } diff --git a/SignalServiceKit/src/Messages/Interactions/TSMention+SDS.swift b/SignalServiceKit/src/Messages/Interactions/TSMention+SDS.swift index 40504109e2..7f77bb9998 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMention+SDS.swift +++ b/SignalServiceKit/src/Messages/Interactions/TSMention+SDS.swift @@ -375,8 +375,6 @@ public extension TSMention { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return TSMention.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(MentionRecord.databaseTableName) WHERE \(mentionColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -407,14 +405,6 @@ public extension TSMention { batchSize: UInt, block: @escaping (TSMention, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - TSMention.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? TSMention else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = TSMention.grdbFetchCursor(transaction: grdbTransaction) @@ -456,10 +446,6 @@ public extension TSMention { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: TSMention.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -491,8 +477,6 @@ public extension TSMention { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: TSMention.collection()) case .grdbRead(let grdbTransaction): return MentionRecord.ows_fetchCount(grdbTransaction.database) } @@ -502,8 +486,6 @@ public extension TSMention { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: TSMention.collection()) case .grdbWrite(let grdbTransaction): do { try MentionRecord.deleteAll(grdbTransaction.database) @@ -552,8 +534,6 @@ public extension TSMention { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: TSMention.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(MentionRecord.databaseTableName) WHERE \(mentionColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.m b/SignalServiceKit/src/Messages/Interactions/TSMessage.m index d244aeb254..adf37d5e6b 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.m @@ -661,12 +661,7 @@ static const NSUInteger OWSMessageSchemaVersion = 4; [self removeAllReactionsWithTransaction:transaction]; - // This path gets hit during the YDB->GRDB migration *tests*, at which point - // it's unsafe to assume we have a GRDB transaction. We can safely skip this - // step during the tests when we don't. - if (!transaction.isYapWrite) { - [self removeAllMentionsWithTransaction:transaction]; - } + [self removeAllMentionsWithTransaction:transaction]; } - (void)removeAllAttachmentsWithTransaction:(SDSAnyWriteTransaction *)transaction diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m index 6e52056875..646878a35c 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m @@ -19,8 +19,6 @@ #import #import #import -#import -#import NS_ASSUME_NONNULL_BEGIN @@ -201,28 +199,7 @@ NSUInteger const TSOutgoingMessageSchemaVersion = 1; self = [super initWithCoder:coder]; if (self) { - if (self.outgoingMessageSchemaVersion < 1) { - OWSAssertDebug(_recipientAddressStates == nil); - - NSMutableDictionary *recipientAddressStates = - [NSMutableDictionary new]; - - NSDictionary *_Nullable legacyStateMap = - [coder decodeObjectForKey:@"recipientStateMap"]; - if (legacyStateMap == nil) { - legacyStateMap = [self createLegacyRecipientStateMapWithCoder:coder]; - } - OWSAssertDebug(legacyStateMap); - for (NSString *phoneNumber in legacyStateMap) { - SignalServiceAddress *address = [[SignalServiceAddress alloc] initWithPhoneNumber:phoneNumber]; - if (!address.isValid) { - OWSFailDebug(@"Ignoring invalid address."); - continue; - } - recipientAddressStates[address] = legacyStateMap[phoneNumber]; - } - _recipientAddressStates = recipientAddressStates; - } + OWSAssertDebug(self.outgoingMessageSchemaVersion >= 1); _outgoingMessageSchemaVersion = TSOutgoingMessageSchemaVersion; } @@ -231,126 +208,6 @@ NSUInteger const TSOutgoingMessageSchemaVersion = 1; return self; } -- (NSDictionary *)createLegacyRecipientStateMapWithCoder:(NSCoder *)coder -{ - OWSAssertDebug(SSKEnvironment.shared.databaseStorage.canReadFromYdb); - OWSAssertDebug(coder); - - // Determine the "overall message state." - TSOutgoingMessageState oldMessageState = TSOutgoingMessageStateFailed; - NSNumber *_Nullable messageStateValue = [coder decodeObjectForKey:@"messageState"]; - if (messageStateValue) { - oldMessageState = (TSOutgoingMessageState)messageStateValue.intValue; - } - _hasLegacyMessageState = YES; - _legacyMessageState = oldMessageState; - - OWSOutgoingMessageRecipientState defaultState; - switch (oldMessageState) { - case TSOutgoingMessageStateFailed: - defaultState = OWSOutgoingMessageRecipientStateFailed; - break; - case TSOutgoingMessageStateSending: - defaultState = OWSOutgoingMessageRecipientStateSending; - break; - case TSOutgoingMessageStateSent: - case TSOutgoingMessageStateSent_OBSOLETE: - case TSOutgoingMessageStateDelivered_OBSOLETE: - // Convert legacy values. - defaultState = OWSOutgoingMessageRecipientStateSent; - break; - } - - // Try to leverage the "per-recipient state." - NSDictionary *_Nullable recipientDeliveryMap = - [coder decodeObjectForKey:@"recipientDeliveryMap"]; - NSDictionary *_Nullable recipientReadMap = [coder decodeObjectForKey:@"recipientReadMap"]; - NSArray *_Nullable sentRecipients = [coder decodeObjectForKey:@"sentRecipients"]; - - NSMutableDictionary *recipientStateMap = [NSMutableDictionary new]; - __block BOOL isGroupThread = NO; - // Our default recipient list is the current thread members. - __block NSArray *recipientIds = @[]; - // To avoid deadlock while migrating these records, we use a dedicated - // migration connection. For legacy records (created more than ~9 months - // before the migration), we need to infer the recipient list for this - // message from the current thread membership. This inference isn't - // always accurate, so not using the same connection for both reads is - // acceptable. - [TSOutgoingMessage.dbMigrationConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - TSThread *thread = [self threadWithTransaction:transaction.asAnyRead]; - NSMutableArray *idsFromAddresses = [NSMutableArray new]; - for (SignalServiceAddress *address in [thread recipientAddresses]) { - if (!address.phoneNumber) { - continue; - } - [idsFromAddresses addObject:address.phoneNumber]; - } - recipientIds = [idsFromAddresses copy]; - isGroupThread = [thread isGroupThread]; - }]; - - NSNumber *_Nullable wasDelivered = [coder decodeObjectForKey:@"wasDelivered"]; - _legacyWasDelivered = wasDelivered && wasDelivered.boolValue; - BOOL wasDeliveredToContact = NO; - if (isGroupThread) { - // If we have a `sentRecipients` list, prefer that as it is more accurate. - if (sentRecipients) { - recipientIds = sentRecipients; - } - } else { - // Special-case messages in contact threads; if "was delivered", we know - // it was delivered to the contact. - wasDeliveredToContact = _legacyWasDelivered; - } - - NSString *_Nullable singleGroupRecipient = [coder decodeObjectForKey:@"singleGroupRecipient"]; - if (singleGroupRecipient) { - OWSFailDebug(@"unexpected single group recipient message."); - // If this is a "single group recipient message", treat it as such. - recipientIds = @[ - singleGroupRecipient, - ]; - } - - for (NSString *recipientId in recipientIds) { - TSOutgoingMessageRecipientState *recipientState = [TSOutgoingMessageRecipientState new]; - - NSNumber *_Nullable readTimestamp = recipientReadMap[recipientId]; - NSNumber *_Nullable deliveryTimestamp = recipientDeliveryMap[recipientId]; - if (readTimestamp) { - // If we have a read timestamp for this recipient, mark it as read. - recipientState.state = OWSOutgoingMessageRecipientStateSent; - recipientState.readTimestamp = readTimestamp; - // deliveryTimestamp might be nil here. - recipientState.deliveryTimestamp = deliveryTimestamp; - } else if (deliveryTimestamp) { - // If we have a delivery timestamp for this recipient, mark it as delivered. - recipientState.state = OWSOutgoingMessageRecipientStateSent; - recipientState.deliveryTimestamp = deliveryTimestamp; - } else if (wasDeliveredToContact) { - OWSAssertDebug(!isGroupThread); - recipientState.state = OWSOutgoingMessageRecipientStateSent; - // Use message time as an estimate of delivery time. - recipientState.deliveryTimestamp = @(self.timestamp); - } else if ([sentRecipients containsObject:recipientId]) { - // If this recipient is in `sentRecipients`, mark it as sent. - recipientState.state = OWSOutgoingMessageRecipientStateSent; - } else { - // Use the default state for this message. - recipientState.state = defaultState; - } - - recipientStateMap[recipientId] = recipientState; - } - return [recipientStateMap copy]; -} - -+ (YapDatabaseConnection *)dbMigrationConnection -{ - return SSKEnvironment.shared.migrationDBConnection; -} - + (instancetype)outgoingMessageInThread:(TSThread *)thread messageBody:(nullable NSString *)body attachmentId:(nullable NSString *)attachmentId @@ -586,30 +443,18 @@ NSUInteger const TSOutgoingMessageSchemaVersion = 1; return NO; } -// POST GRDB TODO: Remove this override. -- (void)ydb_saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - _storedMessageState = self.messageState; - - [super ydb_saveWithTransaction:transaction]; -} - - (void)anyWillInsertWithTransaction:(SDSAnyWriteTransaction *)transaction { [super anyWillInsertWithTransaction:transaction]; - if (transaction.transitional_yapWriteTransaction == nil) { - _storedMessageState = self.messageState; - } + _storedMessageState = self.messageState; } - (void)anyWillUpdateWithTransaction:(SDSAnyWriteTransaction *)transaction { [super anyWillUpdateWithTransaction:transaction]; - if (transaction.transitional_yapWriteTransaction == nil) { - _storedMessageState = self.messageState; - } + _storedMessageState = self.messageState; } // This method will be called after every insert and update, so it needs diff --git a/SignalServiceKit/src/Messages/OWSAddToProfileWhitelistOfferMessage.m b/SignalServiceKit/src/Messages/OWSAddToProfileWhitelistOfferMessage.m index b1e7376d91..cbf1086e1d 100644 --- a/SignalServiceKit/src/Messages/OWSAddToProfileWhitelistOfferMessage.m +++ b/SignalServiceKit/src/Messages/OWSAddToProfileWhitelistOfferMessage.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // #import "OWSAddToProfileWhitelistOfferMessage.h" @@ -7,6 +7,7 @@ NS_ASSUME_NONNULL_BEGIN +// TODO: Cull? // This is a deprecated class, we're keeping it around to avoid YapDB serialization errors // TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject) #pragma clang diagnostic push diff --git a/SignalServiceKit/src/Messages/OWSDisappearingMessagesFinder.h b/SignalServiceKit/src/Messages/OWSDisappearingMessagesFinder.h index 710e04f04f..5bf983d457 100644 --- a/SignalServiceKit/src/Messages/OWSDisappearingMessagesFinder.h +++ b/SignalServiceKit/src/Messages/OWSDisappearingMessagesFinder.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // NS_ASSUME_NONNULL_BEGIN @@ -8,16 +8,12 @@ NS_ASSUME_NONNULL_BEGIN @class SDSAnyReadTransaction; @class TSMessage; @class TSThread; -@class YapDatabaseReadTransaction; @interface OWSDisappearingMessagesFinder : NSObject - (void)enumerateExpiredMessagesWithBlock:(void (^_Nonnull)(TSMessage *message))block transaction:(SDSAnyReadTransaction *)transaction; -+ (void)ydb_enumerateMessagesWhichFailedToStartExpiringWithBlock:(void (^_Nonnull)(TSMessage *message, BOOL *stop))block - transaction:(YapDatabaseReadTransaction *)transaction; - - (void)enumerateMessagesWhichFailedToStartExpiringWithBlock:(void (^_Nonnull)(TSMessage *message, BOOL *stop))block transaction:(SDSAnyReadTransaction *)transaction; @@ -28,23 +24,6 @@ NS_ASSUME_NONNULL_BEGIN */ - (nullable NSNumber *)nextExpirationTimestampWithTransaction:(SDSAnyReadTransaction *_Nonnull)transaction; -+ (void)ydb_enumerateMessagesWithStartedPerConversationExpirationWithBlock:(void (^_Nonnull)( - TSMessage *message, BOOL *stop))block - transaction:(YapDatabaseReadTransaction *)transaction; - -+ (NSArray *)ydb_interactionIdsWithExpiredPerConversationExpirationWithTransaction: - (YapDatabaseReadTransaction *)transaction; - -#ifdef DEBUG -+ (void)ydb_enumerateUnstartedExpiringMessagesWithThreadId:(NSString *)threadId - block:(void (^_Nonnull)(TSMessage *message, BOOL *stop))block - transaction:(YapDatabaseReadTransaction *)transaction; -#endif - -+ (NSString *)databaseExtensionName; - -+ (void)asyncRegisterDatabaseExtensions:(OWSStorage *)storage; - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSDisappearingMessagesFinder.m b/SignalServiceKit/src/Messages/OWSDisappearingMessagesFinder.m index 8253b9ac62..228d163d28 100644 --- a/SignalServiceKit/src/Messages/OWSDisappearingMessagesFinder.m +++ b/SignalServiceKit/src/Messages/OWSDisappearingMessagesFinder.m @@ -1,53 +1,19 @@ // -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // #import "OWSDisappearingMessagesFinder.h" -#import "OWSStorage.h" #import "TSIncomingMessage.h" #import "TSMessage.h" #import "TSOutgoingMessage.h" #import "TSThread.h" #import #import -#import -#import -#import NS_ASSUME_NONNULL_BEGIN -static NSString *const OWSDisappearingMessageFinderThreadIdColumn = @"thread_id"; -static NSString *const OWSDisappearingMessageFinderExpiresAtColumn = @"expires_at"; -static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_messages_on_expires_at_and_thread_id_v2"; - @implementation OWSDisappearingMessagesFinder -+ (NSArray *)ydb_unstartedExpiringMessageIdsWithThreadId:(NSString *)threadId - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - - NSMutableArray *messageIds = [NSMutableArray new]; - NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ = 0 AND %@ = \"%@\"", - OWSDisappearingMessageFinderExpiresAtColumn, - OWSDisappearingMessageFinderThreadIdColumn, - threadId]; - - YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString]; - YapDatabaseSecondaryIndexTransaction *_Nullable ext = - [transaction ext:OWSDisappearingMessageFinderExpiresAtIndex]; - if (!ext) { - [OWSStorage incrementVersionOfDatabaseExtension:OWSDisappearingMessageFinderExpiresAtIndex]; - return @[]; - } - [ext enumerateKeysMatchingQuery:query - usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) { - [messageIds addObject:key]; - }]; - - return [messageIds copy]; -} - - (NSArray *)fetchExpiredMessageIdsWithTransaction:(SDSAnyReadTransaction *)transaction { OWSAssertDebug(transaction); @@ -55,32 +21,6 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess return [InteractionFinder interactionIdsWithExpiredPerConversationExpirationWithTransaction:transaction]; } -+ (NSArray *)ydb_interactionIdsWithExpiredPerConversationExpirationWithTransaction: - (YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - - NSMutableArray *messageIds = [NSMutableArray new]; - - uint64_t now = [NSDate ows_millisecondTimeStamp]; - // When (expiresAt == 0) the message SHOULD NOT expire. Careful ;) - NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ > 0 AND %@ <= %lld", - OWSDisappearingMessageFinderExpiresAtColumn, - OWSDisappearingMessageFinderExpiresAtColumn, - now]; - YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString]; - YapDatabaseSecondaryIndexTransaction *_Nullable ext = [transaction ext:OWSDisappearingMessageFinderExpiresAtIndex]; - if (!ext) { - [OWSStorage incrementVersionOfDatabaseExtension:OWSDisappearingMessageFinderExpiresAtIndex]; - return @[]; - } - [ext enumerateKeysMatchingQuery:query - usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) { - [messageIds addObject:key]; - }]; - return [messageIds copy]; -} - - (nullable NSNumber *)nextExpirationTimestampWithTransaction:(SDSAnyReadTransaction *)transaction { OWSAssertDebug(transaction); @@ -105,67 +45,6 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess return nil; } -+ (void)ydb_enumerateMessagesWithStartedPerConversationExpirationWithBlock:(void (^_Nonnull)( - TSMessage *message, BOOL *stop))block - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(block); - OWSAssertDebug(transaction); - - NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ > 0 ORDER BY %@ ASC", - OWSDisappearingMessageFinderExpiresAtColumn, - OWSDisappearingMessageFinderExpiresAtColumn]; - YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString]; - - YapDatabaseSecondaryIndexTransaction *_Nullable ext = [transaction ext:OWSDisappearingMessageFinderExpiresAtIndex]; - if (!ext) { - [OWSStorage incrementVersionOfDatabaseExtension:OWSDisappearingMessageFinderExpiresAtIndex]; - return; - } - [ext enumerateKeysAndObjectsMatchingQuery:query - usingBlock:^void(NSString *collection, NSString *key, id object, BOOL *stop) { - if (![object isKindOfClass:[TSMessage class]]) { - OWSFailDebug(@"Unexpected object."); - return; - } - TSMessage *message = (TSMessage *)object; - block(message, stop); - }]; -} - -+ (void)ydb_enumerateMessagesWhichFailedToStartExpiringWithBlock:(void (^_Nonnull)(TSMessage *message, BOOL *stop))block - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - - NSString *formattedString = - [NSString stringWithFormat:@"WHERE %@ = 0", OWSDisappearingMessageFinderExpiresAtColumn]; - YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString]; - YapDatabaseSecondaryIndexTransaction *_Nullable ext = [transaction ext:OWSDisappearingMessageFinderExpiresAtIndex]; - if (!ext) { - [OWSStorage incrementVersionOfDatabaseExtension:OWSDisappearingMessageFinderExpiresAtIndex]; - return; - } - [ext enumerateKeysAndObjectsMatchingQuery:query - usingBlock:^void(NSString *collection, NSString *key, id object, BOOL *stop) { - if (![object isKindOfClass:[TSMessage class]]) { - OWSFailDebug(@"Object was unexpected class: %@", [object class]); - return; - } - TSMessage *message = (TSMessage *)object; - if (![message shouldStartExpireTimer]) { - OWSFailDebug(@"object: %@ shouldn't expire.", message); - return; - } - - if ([message isKindOfClass:[TSIncomingMessage class]]) { - TSIncomingMessage *incomingMessage = (TSIncomingMessage *)message; - OWSAssertDebug(incomingMessage.wasRead); - } - block(message, stop); - }]; -} - - (void)enumerateMessagesWhichFailedToStartExpiringWithBlock:(void (^_Nonnull)(TSMessage *message, BOOL *stop))block transaction:(SDSAnyReadTransaction *)transaction { @@ -175,39 +54,6 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess } #ifdef DEBUG - -/** - * Don't use this in production. Useful for testing. - * We don't want to instantiate potentially many messages at once. - */ -+ (void)ydb_enumerateUnstartedExpiringMessagesWithThreadId:(NSString *)threadId - block:(void (^_Nonnull)(TSMessage *message, BOOL *stop))block - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - - NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ = 0 AND %@ = \"%@\"", - OWSDisappearingMessageFinderExpiresAtColumn, - OWSDisappearingMessageFinderThreadIdColumn, - threadId]; - - YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString]; - YapDatabaseSecondaryIndexTransaction *_Nullable ext = [transaction ext:OWSDisappearingMessageFinderExpiresAtIndex]; - if (!ext) { - [OWSStorage incrementVersionOfDatabaseExtension:OWSDisappearingMessageFinderExpiresAtIndex]; - return; - } - [ext enumerateKeysAndObjectsMatchingQuery:query - usingBlock:^void(NSString *collection, NSString *key, id object, BOOL *stop) { - if (![object isKindOfClass:[TSMessage class]]) { - OWSFailDebug(@"Unexpected object."); - return; - } - TSMessage *message = (TSMessage *)object; - block(message, stop); - }]; -} - /** * Don't use this in production. Useful for testing. * We don't want to instantiate potentially many messages at once. @@ -225,7 +71,6 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess }]; return [messages copy]; } - #endif - (void)enumerateExpiredMessagesWithBlock:(void (^_Nonnull)(TSMessage *message))block @@ -264,46 +109,6 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess } #endif -#pragma mark - YapDatabaseExtension - -+ (YapDatabaseSecondaryIndex *)indexDatabaseExtension -{ - YapDatabaseSecondaryIndexSetup *setup = [YapDatabaseSecondaryIndexSetup new]; - [setup addColumn:OWSDisappearingMessageFinderExpiresAtColumn withType:YapDatabaseSecondaryIndexTypeInteger]; - [setup addColumn:OWSDisappearingMessageFinderThreadIdColumn withType:YapDatabaseSecondaryIndexTypeText]; - - YapDatabaseSecondaryIndexHandler *handler = - [YapDatabaseSecondaryIndexHandler withObjectBlock:^(YapDatabaseReadTransaction *transaction, - NSMutableDictionary *dict, - NSString *collection, - NSString *key, - id object) { - if (![object isKindOfClass:[TSMessage class]]) { - return; - } - TSMessage *message = (TSMessage *)object; - - if (![message shouldStartExpireTimer]) { - return; - } - - dict[OWSDisappearingMessageFinderExpiresAtColumn] = @(message.expiresAt); - dict[OWSDisappearingMessageFinderThreadIdColumn] = message.uniqueThreadId; - }]; - - return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler versionTag:@"4"]; -} - -+ (NSString *)databaseExtensionName -{ - return OWSDisappearingMessageFinderExpiresAtIndex; -} - -+ (void)asyncRegisterDatabaseExtensions:(OWSStorage *)storage -{ - [storage asyncRegisterExtension:[self indexDatabaseExtension] withName:OWSDisappearingMessageFinderExpiresAtIndex]; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSFailedAttachmentDownloadsJob.h b/SignalServiceKit/src/Messages/OWSFailedAttachmentDownloadsJob.h index f3f9f246e0..60378dffd3 100644 --- a/SignalServiceKit/src/Messages/OWSFailedAttachmentDownloadsJob.h +++ b/SignalServiceKit/src/Messages/OWSFailedAttachmentDownloadsJob.h @@ -1,21 +1,13 @@ // -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // NS_ASSUME_NONNULL_BEGIN -@class OWSStorage; -@class YapDatabaseReadTransaction; - @interface OWSFailedAttachmentDownloadsJob : NSObject - (void)runSync; -+ (NSArray *)unfailedAttachmentPointerIdsWithTransaction:(YapDatabaseReadTransaction *)transaction; - -+ (NSString *)databaseExtensionName; -+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage; - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSFailedAttachmentDownloadsJob.m b/SignalServiceKit/src/Messages/OWSFailedAttachmentDownloadsJob.m index 547b215dad..d9076ce6ad 100644 --- a/SignalServiceKit/src/Messages/OWSFailedAttachmentDownloadsJob.m +++ b/SignalServiceKit/src/Messages/OWSFailedAttachmentDownloadsJob.m @@ -3,39 +3,13 @@ // #import "OWSFailedAttachmentDownloadsJob.h" -#import "OWSPrimaryStorage.h" #import "TSAttachmentPointer.h" #import -#import -#import -#import NS_ASSUME_NONNULL_BEGIN -static NSString *const OWSFailedAttachmentDownloadsJobAttachmentStateColumn = @"state"; -static NSString *const OWSFailedAttachmentDownloadsJobAttachmentStateIndex = @"index_attachment_downloads_on_state"; - @implementation OWSFailedAttachmentDownloadsJob -+ (NSArray *)unfailedAttachmentPointerIdsWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - - NSMutableArray *attachmentIds = [NSMutableArray new]; - - NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ != %d", - OWSFailedAttachmentDownloadsJobAttachmentStateColumn, - (int)TSAttachmentPointerStateFailed]; - YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString]; - [[transaction ext:OWSFailedAttachmentDownloadsJobAttachmentStateIndex] - enumerateKeysMatchingQuery:query - usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) { - [attachmentIds addObject:key]; - }]; - - return [attachmentIds copy]; -} - - (void)enumerateAttemptingOutAttachmentsWithBlock:(void (^_Nonnull)(TSAttachmentPointer *attachment))block transaction:(SDSAnyReadTransaction *)transaction { @@ -94,41 +68,6 @@ static NSString *const OWSFailedAttachmentDownloadsJobAttachmentStateIndex = @"i } } -#pragma mark - YapDatabaseExtension - -+ (YapDatabaseSecondaryIndex *)indexDatabaseExtension -{ - YapDatabaseSecondaryIndexSetup *setup = [YapDatabaseSecondaryIndexSetup new]; - [setup addColumn:OWSFailedAttachmentDownloadsJobAttachmentStateColumn - withType:YapDatabaseSecondaryIndexTypeInteger]; - - YapDatabaseSecondaryIndexHandler *handler = - [YapDatabaseSecondaryIndexHandler withObjectBlock:^(YapDatabaseReadTransaction *transaction, - NSMutableDictionary *dict, - NSString *collection, - NSString *key, - id object) { - if (![object isKindOfClass:[TSAttachmentPointer class]]) { - return; - } - TSAttachmentPointer *attachment = (TSAttachmentPointer *)object; - dict[OWSFailedAttachmentDownloadsJobAttachmentStateColumn] = @(attachment.state); - }]; - - return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler versionTag:nil]; -} - -+ (NSString *)databaseExtensionName -{ - return OWSFailedAttachmentDownloadsJobAttachmentStateIndex; -} - -+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage -{ - [storage asyncRegisterExtension:[self indexDatabaseExtension] - withName:OWSFailedAttachmentDownloadsJobAttachmentStateIndex]; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSFailedMessagesJob.h b/SignalServiceKit/src/Messages/OWSFailedMessagesJob.h index 550e9fe2ff..07fb3d92e1 100644 --- a/SignalServiceKit/src/Messages/OWSFailedMessagesJob.h +++ b/SignalServiceKit/src/Messages/OWSFailedMessagesJob.h @@ -1,21 +1,13 @@ // -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // NS_ASSUME_NONNULL_BEGIN -@class OWSStorage; -@class YapDatabaseReadTransaction; - @interface OWSFailedMessagesJob : NSObject - (void)runSync; -+ (NSArray *)attemptingOutMessageIdsWithTransaction:(YapDatabaseReadTransaction *)transaction; - -+ (NSString *)databaseExtensionName; -+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage; - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSFailedMessagesJob.m b/SignalServiceKit/src/Messages/OWSFailedMessagesJob.m index e1c9b5018f..5cd403d40c 100644 --- a/SignalServiceKit/src/Messages/OWSFailedMessagesJob.m +++ b/SignalServiceKit/src/Messages/OWSFailedMessagesJob.m @@ -3,19 +3,12 @@ // #import "OWSFailedMessagesJob.h" -#import "OWSStorage.h" #import "TSMessage.h" #import "TSOutgoingMessage.h" #import -#import -#import -#import NS_ASSUME_NONNULL_BEGIN -static NSString *const OWSFailedMessagesJobMessageStateColumn = @"message_state"; -static NSString *const OWSFailedMessagesJobMessageStateIndex = @"index_outoing_messages_on_message_state"; - @implementation OWSFailedMessagesJob - (NSArray *)fetchAttemptingOutMessageIdsWithTransaction:(SDSAnyReadTransaction *)transaction @@ -25,24 +18,6 @@ static NSString *const OWSFailedMessagesJobMessageStateIndex = @"index_outoing_m return [InteractionFinder attemptingOutInteractionIdsWithTransaction:transaction]; } -+ (NSArray *)attemptingOutMessageIdsWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - - NSMutableArray *messageIds = [NSMutableArray new]; - - NSString *formattedString = [NSString - stringWithFormat:@"WHERE %@ == %d", OWSFailedMessagesJobMessageStateColumn, (int)TSOutgoingMessageStateSending]; - YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString]; - [[transaction ext:OWSFailedMessagesJobMessageStateIndex] - enumerateKeysMatchingQuery:query - usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) { - [messageIds addObject:key]; - }]; - - return [messageIds copy]; -} - - (void)enumerateAttemptingOutMessagesWithBlock:(void (^_Nonnull)(TSOutgoingMessage *message))block transaction:(SDSAnyReadTransaction *)transaction { @@ -87,40 +62,6 @@ static NSString *const OWSFailedMessagesJobMessageStateIndex = @"index_outoing_m OWSLogDebug(@"Marked %u messages as unsent", count); } -#pragma mark - YapDatabaseExtension - -+ (YapDatabaseSecondaryIndex *)indexDatabaseExtension -{ - YapDatabaseSecondaryIndexSetup *setup = [YapDatabaseSecondaryIndexSetup new]; - [setup addColumn:OWSFailedMessagesJobMessageStateColumn withType:YapDatabaseSecondaryIndexTypeInteger]; - - YapDatabaseSecondaryIndexHandler *handler = - [YapDatabaseSecondaryIndexHandler withObjectBlock:^(YapDatabaseReadTransaction *transaction, - NSMutableDictionary *dict, - NSString *collection, - NSString *key, - id object) { - if (![object isKindOfClass:[TSOutgoingMessage class]]) { - return; - } - TSOutgoingMessage *message = (TSOutgoingMessage *)object; - - dict[OWSFailedMessagesJobMessageStateColumn] = @(message.messageState); - }]; - - return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler versionTag:nil]; -} - -+ (NSString *)databaseExtensionName -{ - return OWSFailedMessagesJobMessageStateIndex; -} - -+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage -{ - [storage asyncRegisterExtension:[self indexDatabaseExtension] withName:OWSFailedMessagesJobMessageStateIndex]; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSIncompleteCallsJob.h b/SignalServiceKit/src/Messages/OWSIncompleteCallsJob.h index 9a47bbdeda..829e3462cd 100644 --- a/SignalServiceKit/src/Messages/OWSIncompleteCallsJob.h +++ b/SignalServiceKit/src/Messages/OWSIncompleteCallsJob.h @@ -1,21 +1,13 @@ // -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // NS_ASSUME_NONNULL_BEGIN -@class OWSStorage; -@class YapDatabaseReadTransaction; - @interface OWSIncompleteCallsJob : NSObject - (void)runSync; -+ (NSArray *)ydb_incompleteCallIdsWithTransaction:(YapDatabaseReadTransaction *)transaction; - -+ (NSString *)databaseExtensionName; -+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage; - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSIncompleteCallsJob.m b/SignalServiceKit/src/Messages/OWSIncompleteCallsJob.m index 892af98f2e..f75adbc1fd 100644 --- a/SignalServiceKit/src/Messages/OWSIncompleteCallsJob.m +++ b/SignalServiceKit/src/Messages/OWSIncompleteCallsJob.m @@ -4,21 +4,12 @@ #import "OWSIncompleteCallsJob.h" #import "AppContext.h" -#import "OWSPrimaryStorage.h" #import "TSCall.h" #import #import -#import -#import -#import NS_ASSUME_NONNULL_BEGIN -static NSString *const OWSIncompleteCallsJobCallTypeColumn = @"call_type"; -static NSString *const OWSIncompleteCallsJobCallTypeIndex = @"index_calls_on_call_type"; - -#pragma mark - - @implementation OWSIncompleteCallsJob - (NSArray *)fetchIncompleteCallIdsWithTransaction:(SDSAnyWriteTransaction *)transaction @@ -28,27 +19,6 @@ static NSString *const OWSIncompleteCallsJobCallTypeIndex = @"index_calls_on_cal return [InteractionFinder incompleteCallIdsWithTransaction:transaction]; } -+ (NSArray *)ydb_incompleteCallIdsWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - - NSMutableArray *messageIds = [NSMutableArray new]; - - NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ == %d OR %@ == %d", - OWSIncompleteCallsJobCallTypeColumn, - (int)RPRecentCallTypeOutgoingIncomplete, - OWSIncompleteCallsJobCallTypeColumn, - (int)RPRecentCallTypeIncomingIncomplete]; - YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString]; - [[transaction ext:OWSIncompleteCallsJobCallTypeIndex] - enumerateKeysMatchingQuery:query - usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) { - [messageIds addObject:key]; - }]; - - return [messageIds copy]; -} - - (void)enumerateIncompleteCallsWithBlock:(void (^)(TSCall *call))block transaction:(SDSAnyWriteTransaction *)transaction { @@ -101,40 +71,6 @@ static NSString *const OWSIncompleteCallsJobCallTypeIndex = @"index_calls_on_cal OWSLogInfo(@"Marked %u calls as missed", count); } -#pragma mark - YapDatabaseExtension - -+ (YapDatabaseSecondaryIndex *)indexDatabaseExtension -{ - YapDatabaseSecondaryIndexSetup *setup = [YapDatabaseSecondaryIndexSetup new]; - [setup addColumn:OWSIncompleteCallsJobCallTypeColumn withType:YapDatabaseSecondaryIndexTypeInteger]; - - YapDatabaseSecondaryIndexHandler *handler = - [YapDatabaseSecondaryIndexHandler withObjectBlock:^(YapDatabaseReadTransaction *transaction, - NSMutableDictionary *dict, - NSString *collection, - NSString *key, - id object) { - if (![object isKindOfClass:[TSCall class]]) { - return; - } - TSCall *call = (TSCall *)object; - - dict[OWSIncompleteCallsJobCallTypeColumn] = @(call.callType); - }]; - - return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler versionTag:nil]; -} - -+ (NSString *)databaseExtensionName -{ - return OWSIncompleteCallsJobCallTypeIndex; -} - -+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage -{ - [storage asyncRegisterExtension:[self indexDatabaseExtension] withName:OWSIncompleteCallsJobCallTypeIndex]; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSMessageContentJob+SDS.swift b/SignalServiceKit/src/Messages/OWSMessageContentJob+SDS.swift index 27e61b7919..90c8384c03 100644 --- a/SignalServiceKit/src/Messages/OWSMessageContentJob+SDS.swift +++ b/SignalServiceKit/src/Messages/OWSMessageContentJob+SDS.swift @@ -384,8 +384,6 @@ public extension OWSMessageContentJob { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return OWSMessageContentJob.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(MessageContentJobRecord.databaseTableName) WHERE \(messageContentJobColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -416,14 +414,6 @@ public extension OWSMessageContentJob { batchSize: UInt, block: @escaping (OWSMessageContentJob, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - OWSMessageContentJob.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? OWSMessageContentJob else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = OWSMessageContentJob.grdbFetchCursor(transaction: grdbTransaction) @@ -465,10 +455,6 @@ public extension OWSMessageContentJob { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: OWSMessageContentJob.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -500,8 +486,6 @@ public extension OWSMessageContentJob { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: OWSMessageContentJob.collection()) case .grdbRead(let grdbTransaction): return MessageContentJobRecord.ows_fetchCount(grdbTransaction.database) } @@ -511,8 +495,6 @@ public extension OWSMessageContentJob { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: OWSMessageContentJob.collection()) case .grdbWrite(let grdbTransaction): do { try MessageContentJobRecord.deleteAll(grdbTransaction.database) @@ -561,8 +543,6 @@ public extension OWSMessageContentJob { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: OWSMessageContentJob.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(MessageContentJobRecord.databaseTableName) WHERE \(messageContentJobColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Messages/OWSMessageDecryptJob+SDS.swift b/SignalServiceKit/src/Messages/OWSMessageDecryptJob+SDS.swift index c1a97e1ac0..6727569c0e 100644 --- a/SignalServiceKit/src/Messages/OWSMessageDecryptJob+SDS.swift +++ b/SignalServiceKit/src/Messages/OWSMessageDecryptJob+SDS.swift @@ -366,8 +366,6 @@ public extension OWSMessageDecryptJob { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return OWSMessageDecryptJob.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(MessageDecryptJobRecord.databaseTableName) WHERE \(messageDecryptJobColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -398,14 +396,6 @@ public extension OWSMessageDecryptJob { batchSize: UInt, block: @escaping (OWSMessageDecryptJob, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - OWSMessageDecryptJob.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? OWSMessageDecryptJob else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = OWSMessageDecryptJob.grdbFetchCursor(transaction: grdbTransaction) @@ -447,10 +437,6 @@ public extension OWSMessageDecryptJob { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: OWSMessageDecryptJob.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -482,8 +468,6 @@ public extension OWSMessageDecryptJob { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: OWSMessageDecryptJob.collection()) case .grdbRead(let grdbTransaction): return MessageDecryptJobRecord.ows_fetchCount(grdbTransaction.database) } @@ -493,8 +477,6 @@ public extension OWSMessageDecryptJob { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: OWSMessageDecryptJob.collection()) case .grdbWrite(let grdbTransaction): do { try MessageDecryptJobRecord.deleteAll(grdbTransaction.database) @@ -543,8 +525,6 @@ public extension OWSMessageDecryptJob { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: OWSMessageDecryptJob.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(MessageDecryptJobRecord.databaseTableName) WHERE \(messageDecryptJobColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Messages/OWSMessageDecryptJob.h b/SignalServiceKit/src/Messages/OWSMessageDecryptJob.h index e17fa60c5d..8a4fbd34b4 100644 --- a/SignalServiceKit/src/Messages/OWSMessageDecryptJob.h +++ b/SignalServiceKit/src/Messages/OWSMessageDecryptJob.h @@ -11,8 +11,6 @@ NS_ASSUME_NONNULL_BEGIN @class SDSAnyWriteTransaction; @class SSKProtoEnvelope; -extern NSNotificationName const kNSNotificationNameMessageDecryptionDidFlushQueue; - @interface OWSMessageDecryptJob : BaseModel @property (nonatomic, readonly) NSDate *createdAt; @@ -49,23 +47,4 @@ NS_DESIGNATED_INITIALIZER NS_SWIFT_NAME(init(grdbId:uniqueId:createdAt:envelopeD @end -#pragma mark - - -@interface OWSMessageDecryptJobFinder : NSObject - -- (NSString *)databaseExtensionName; -- (NSString *)databaseExtensionGroup; - -- (NSUInteger)queuedJobCountWithTransaction:(SDSAnyReadTransaction *)transaction; - -+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage; - -#ifdef DEBUG -- (void)addJobForEnvelopeData:(NSData *)envelopeData - serverDeliveryTimestamp:(uint64_t)serverDeliveryTimestamp - transaction:(SDSAnyWriteTransaction *)transaction; -#endif - -@end - NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSMessageDecryptJob.m b/SignalServiceKit/src/Messages/OWSMessageDecryptJob.m index 73071e6da5..616e0a59c1 100644 --- a/SignalServiceKit/src/Messages/OWSMessageDecryptJob.m +++ b/SignalServiceKit/src/Messages/OWSMessageDecryptJob.m @@ -10,7 +10,6 @@ #import "NotificationsProtocol.h" #import "OWSBackgroundTask.h" #import "OWSQueues.h" -#import "OWSStorage.h" #import "ProfileManagerProtocol.h" #import "SSKEnvironment.h" #import "TSAccountManager.h" @@ -21,9 +20,6 @@ NS_ASSUME_NONNULL_BEGIN -NSNotificationName const kNSNotificationNameMessageDecryptionDidFlushQueue - = @"kNSNotificationNameMessageDecryptionDidFlushQueue"; - @implementation OWSMessageDecryptJob + (NSString *)collection @@ -98,160 +94,4 @@ NSNotificationName const kNSNotificationNameMessageDecryptionDidFlushQueue @end -#pragma mark - Finder - -NSString *const OWSMessageDecryptJobFinderExtensionName = @"OWSMessageProcessingJobFinderExtensionName2"; -NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessingJobFinderExtensionGroup2"; - -@implementation OWSMessageDecryptJobFinder - -- (instancetype)init -{ - self = [super init]; - if (!self) { - return self; - } - - [OWSMessageDecryptJobFinder registerLegacyClasses]; - - return self; -} - -- (NSString *)databaseExtensionName -{ - return OWSMessageDecryptJobFinderExtensionName; -} - -- (NSString *)databaseExtensionGroup -{ - return OWSMessageDecryptJobFinderExtensionGroup; -} - -- (OWSMessageDecryptJob *_Nullable)nextJob -{ - // POST GRDB TODO: Remove this queue & finder entirely. - if (StorageCoordinator.dataStoreForUI != DataStoreYdb) { - OWSLogWarn(@"Not processing queue; obsolete."); - return nil; - } - - __block OWSMessageDecryptJob *_Nullable job = nil; - [self.databaseStorage - readWithBlock:^(SDSAnyReadTransaction *transaction) { job = [self nextJobWithTransaction:transaction]; }]; - return job; -} - -- (void)addJobForEnvelopeData:(NSData *)envelopeData serverDeliveryTimestamp:(uint64_t)serverDeliveryTimestamp -{ - DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) { - [self addJobForEnvelopeData:envelopeData - serverDeliveryTimestamp:serverDeliveryTimestamp - transaction:transaction]; - }); -} - -- (void)addJobForEnvelopeData:(NSData *)envelopeData - serverDeliveryTimestamp:(uint64_t)serverDeliveryTimestamp - transaction:(SDSAnyWriteTransaction *)transaction -{ - OWSMessageDecryptJob *job = [[OWSMessageDecryptJob alloc] initWithEnvelopeData:envelopeData - serverDeliveryTimestamp:serverDeliveryTimestamp]; - [job anyInsertWithTransaction:transaction]; -} - -- (void)removeJobWithId:(NSString *)uniqueId -{ - DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) { - OWSMessageDecryptJob *_Nullable job = [OWSMessageDecryptJob anyFetchWithUniqueId:uniqueId - transaction:transaction]; - if (job) { - [job anyRemoveWithTransaction:transaction]; - } - }); -} - -- (NSUInteger)queuedJobCount -{ - __block NSUInteger result; - [self.databaseStorage readWithBlock:^( - SDSAnyReadTransaction *transaction) { result = [self queuedJobCountWithTransaction:transaction]; }]; - return result; -} - -- (NSUInteger)queuedJobCountWithTransaction:(SDSAnyReadTransaction *)transaction -{ - return [OWSMessageDecryptJob anyCountWithTransaction:transaction]; -} - -+ (YapDatabaseView *)databaseExtension -{ - YapDatabaseViewSorting *sorting = - [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction, - NSString *group, - NSString *collection1, - NSString *key1, - id object1, - NSString *collection2, - NSString *key2, - id object2) { - if (![object1 isKindOfClass:[OWSMessageDecryptJob class]]) { - OWSFailDebug(@"Unexpected object: %@ in collection: %@", [object1 class], collection1); - return NSOrderedSame; - } - OWSMessageDecryptJob *job1 = (OWSMessageDecryptJob *)object1; - - if (![object2 isKindOfClass:[OWSMessageDecryptJob class]]) { - OWSFailDebug(@"Unexpected object: %@ in collection: %@", [object2 class], collection2); - return NSOrderedSame; - } - OWSMessageDecryptJob *job2 = (OWSMessageDecryptJob *)object2; - - return [job1.createdAt compare:job2.createdAt]; - }]; - - YapDatabaseViewGrouping *grouping = - [YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable(YapDatabaseReadTransaction *_Nonnull transaction, - NSString *_Nonnull collection, - NSString *_Nonnull key, - id _Nonnull object) { - if (![object isKindOfClass:[OWSMessageDecryptJob class]]) { - OWSFailDebug(@"Unexpected object: %@ in collection: %@", object, collection); - return nil; - } - - // Arbitrary string - all in the same group. We're only using the view for sorting. - return OWSMessageDecryptJobFinderExtensionGroup; - }]; - - YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; - options.allowedCollections = - [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[OWSMessageDecryptJob collection]]]; - - return [[YapDatabaseAutoView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"1" options:options]; -} - -+ (void)registerLegacyClasses -{ - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - // We've renamed OWSMessageProcessingJob to OWSMessageDecryptJob. - [NSKeyedUnarchiver setClass:[OWSMessageDecryptJob class] forClassName:[OWSMessageDecryptJob collection]]; - }); -} - -+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage -{ - [self registerLegacyClasses]; - - YapDatabaseView *existingView = [storage registeredExtension:OWSMessageDecryptJobFinderExtensionName]; - if (existingView) { - OWSFailDebug(@"%@ was already initialized.", OWSMessageDecryptJobFinderExtensionName); - // already initialized - return; - } - [storage asyncRegisterExtension:[self databaseExtension] withName:OWSMessageDecryptJobFinderExtensionName]; -} - -@end - NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSMessageDecryptJob.swift b/SignalServiceKit/src/Messages/OWSMessageDecryptJob.swift index 34c74ed800..ca0f5e5380 100644 --- a/SignalServiceKit/src/Messages/OWSMessageDecryptJob.swift +++ b/SignalServiceKit/src/Messages/OWSMessageDecryptJob.swift @@ -4,93 +4,3 @@ import Foundation import GRDB - -@objc -public extension OWSMessageDecryptJobFinder { - - func nextJob(transaction: SDSAnyReadTransaction) -> OWSMessageDecryptJob? { - switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return nextJob(ydbTransaction: ydbTransaction) - case .grdbRead(let grdbTransaction): - return nextJob(grdbTransaction: grdbTransaction) - } - } - - private func nextJob(ydbTransaction transaction: YapDatabaseReadTransaction) -> OWSMessageDecryptJob? { - guard let viewTransaction = transaction.safeViewTransaction(databaseExtensionName()) else { - owsFailDebug("Could not load view transaction.") - return nil - } - guard let object = viewTransaction.firstObject(inGroup: databaseExtensionGroup()) else { - return nil - } - guard let job = object as? OWSMessageDecryptJob else { - owsFailDebug("Object has unexpected type: \(type(of: object))") - return nil - } - return job - } - - private func nextJob(grdbTransaction transaction: GRDBReadTransaction) -> OWSMessageDecryptJob? { - owsFailDebug("We should be using SSKMessageDecryptJobQueue instead of this method.") - - let sql = """ - SELECT * - FROM \(MessageDecryptJobRecord.databaseTableName) - ORDER BY \(messageDecryptJobColumn: .createdAt) - LIMIT 1 - """ - return OWSMessageDecryptJob.grdbFetchOne(sql: sql, transaction: transaction) - } - - func enumerateJobs(transaction: SDSAnyReadTransaction, block: @escaping (OWSMessageDecryptJob, UnsafeMutablePointer) -> Void) throws { - switch transaction.readTransaction { - case .yapRead(let yapRead): - return try enumerateJobs(ydbTransaction: yapRead, block: block) - case .grdbRead(let grdbRead): - return try enumerateJobs(grdbTransaction: grdbRead, block: block) - } - } - - private func enumerateJobs(ydbTransaction transaction: YapDatabaseReadTransaction, block: @escaping (OWSMessageDecryptJob, UnsafeMutablePointer) -> Void) throws { - guard let view = transaction.safeViewTransaction(databaseExtensionName()) else { - owsFailDebug("Could not load view transaction.") - return - } - view.safe_enumerateKeysAndObjects(inGroup: databaseExtensionGroup(), - extensionName: databaseExtensionName()) { (_, _, object, _, stopPtr) in - guard let job = object as? OWSMessageDecryptJob else { - owsFailDebug("unexpected job: \(type(of: object))") - return - } - block(job, stopPtr) - } - } - - private func enumerateJobs(grdbTransaction transaction: GRDBReadTransaction, block: @escaping (OWSMessageDecryptJob, UnsafeMutablePointer) -> Void) throws { - owsFailDebug("We should be using SSKMessageDecryptJobQueue instead of this method.") - - let sql = """ - SELECT uniqueId - FROM \(MessageDecryptJobRecord.databaseTableName) - ORDER BY \(messageDecryptJobColumn: .createdAt) - """ - let cursor = try String.fetchCursor(transaction.database, - sql: sql, - arguments: []) - while let jobId = try cursor.next() { - guard let job = OWSMessageDecryptJob.anyFetch(uniqueId: jobId, - transaction: transaction.asAnyRead) else { - owsFailDebug("Missing job") - continue - } - - var stop: ObjCBool = false - block(job, &stop) - if stop.boolValue { - return - } - } - } -} diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 3217f49812..e3f524a432 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -20,7 +20,6 @@ #import "OWSDisappearingMessagesJob.h" #import "OWSGroupInfoRequestMessage.h" #import "OWSIdentityManager.h" -#import "OWSIncomingMessageFinder.h" #import "OWSIncomingSentMessageTranscript.h" #import "OWSMessageUtils.h" #import "OWSOutgoingReceiptManager.h" diff --git a/SignalServiceKit/src/Messages/Reactions/OWSReaction+SDS.swift b/SignalServiceKit/src/Messages/Reactions/OWSReaction+SDS.swift index 135047ad54..d6d9c1e12c 100644 --- a/SignalServiceKit/src/Messages/Reactions/OWSReaction+SDS.swift +++ b/SignalServiceKit/src/Messages/Reactions/OWSReaction+SDS.swift @@ -401,8 +401,6 @@ public extension OWSReaction { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return OWSReaction.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(ReactionRecord.databaseTableName) WHERE \(reactionColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -433,14 +431,6 @@ public extension OWSReaction { batchSize: UInt, block: @escaping (OWSReaction, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - OWSReaction.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? OWSReaction else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = OWSReaction.grdbFetchCursor(transaction: grdbTransaction) @@ -482,10 +472,6 @@ public extension OWSReaction { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: OWSReaction.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -517,8 +503,6 @@ public extension OWSReaction { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: OWSReaction.collection()) case .grdbRead(let grdbTransaction): return ReactionRecord.ows_fetchCount(grdbTransaction.database) } @@ -528,8 +512,6 @@ public extension OWSReaction { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: OWSReaction.collection()) case .grdbWrite(let grdbTransaction): do { try ReactionRecord.deleteAll(grdbTransaction.database) @@ -578,8 +560,6 @@ public extension OWSReaction { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: OWSReaction.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(ReactionRecord.databaseTableName) WHERE \(reactionColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Messages/Stickers/InstalledSticker+SDS.swift b/SignalServiceKit/src/Messages/Stickers/InstalledSticker+SDS.swift index 3991610294..e85edb0f51 100644 --- a/SignalServiceKit/src/Messages/Stickers/InstalledSticker+SDS.swift +++ b/SignalServiceKit/src/Messages/Stickers/InstalledSticker+SDS.swift @@ -384,8 +384,6 @@ public extension InstalledSticker { } switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return InstalledSticker.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(InstalledStickerRecord.databaseTableName) WHERE \(installedStickerColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -416,14 +414,6 @@ public extension InstalledSticker { batchSize: UInt, block: @escaping (InstalledSticker, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - InstalledSticker.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? InstalledSticker else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = InstalledSticker.grdbFetchCursor(transaction: grdbTransaction) @@ -465,10 +455,6 @@ public extension InstalledSticker { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: InstalledSticker.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -500,8 +486,6 @@ public extension InstalledSticker { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: InstalledSticker.collection()) case .grdbRead(let grdbTransaction): return InstalledStickerRecord.ows_fetchCount(grdbTransaction.database) } @@ -511,8 +495,6 @@ public extension InstalledSticker { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: InstalledSticker.collection()) case .grdbWrite(let grdbTransaction): do { try InstalledStickerRecord.deleteAll(grdbTransaction.database) @@ -561,8 +543,6 @@ public extension InstalledSticker { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: InstalledSticker.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(InstalledStickerRecord.databaseTableName) WHERE \(installedStickerColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Messages/Stickers/KnownStickerPack+SDS.swift b/SignalServiceKit/src/Messages/Stickers/KnownStickerPack+SDS.swift index 2442f95c2d..2d81fff490 100644 --- a/SignalServiceKit/src/Messages/Stickers/KnownStickerPack+SDS.swift +++ b/SignalServiceKit/src/Messages/Stickers/KnownStickerPack+SDS.swift @@ -369,8 +369,6 @@ public extension KnownStickerPack { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return KnownStickerPack.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(KnownStickerPackRecord.databaseTableName) WHERE \(knownStickerPackColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -401,14 +399,6 @@ public extension KnownStickerPack { batchSize: UInt, block: @escaping (KnownStickerPack, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - KnownStickerPack.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? KnownStickerPack else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = KnownStickerPack.grdbFetchCursor(transaction: grdbTransaction) @@ -450,10 +440,6 @@ public extension KnownStickerPack { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: KnownStickerPack.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -485,8 +471,6 @@ public extension KnownStickerPack { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: KnownStickerPack.collection()) case .grdbRead(let grdbTransaction): return KnownStickerPackRecord.ows_fetchCount(grdbTransaction.database) } @@ -496,8 +480,6 @@ public extension KnownStickerPack { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: KnownStickerPack.collection()) case .grdbWrite(let grdbTransaction): do { try KnownStickerPackRecord.deleteAll(grdbTransaction.database) @@ -546,8 +528,6 @@ public extension KnownStickerPack { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: KnownStickerPack.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(KnownStickerPackRecord.databaseTableName) WHERE \(knownStickerPackColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Messages/Stickers/StickerPack+SDS.swift b/SignalServiceKit/src/Messages/Stickers/StickerPack+SDS.swift index 301335b4b9..98be55ddda 100644 --- a/SignalServiceKit/src/Messages/Stickers/StickerPack+SDS.swift +++ b/SignalServiceKit/src/Messages/Stickers/StickerPack+SDS.swift @@ -411,8 +411,6 @@ public extension StickerPack { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return StickerPack.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(StickerPackRecord.databaseTableName) WHERE \(stickerPackColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -443,14 +441,6 @@ public extension StickerPack { batchSize: UInt, block: @escaping (StickerPack, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - StickerPack.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? StickerPack else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = StickerPack.grdbFetchCursor(transaction: grdbTransaction) @@ -492,10 +482,6 @@ public extension StickerPack { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: StickerPack.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -527,8 +513,6 @@ public extension StickerPack { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: StickerPack.collection()) case .grdbRead(let grdbTransaction): return StickerPackRecord.ows_fetchCount(grdbTransaction.database) } @@ -538,8 +522,6 @@ public extension StickerPack { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: StickerPack.collection()) case .grdbWrite(let grdbTransaction): do { try StickerPackRecord.deleteAll(grdbTransaction.database) @@ -588,8 +570,6 @@ public extension StickerPack { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: StickerPack.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(StickerPackRecord.databaseTableName) WHERE \(stickerPackColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Network/Receiving/IncomingGroupsV2MessageJob+SDS.swift b/SignalServiceKit/src/Network/Receiving/IncomingGroupsV2MessageJob+SDS.swift index d884ad4e4c..65763e27ee 100644 --- a/SignalServiceKit/src/Network/Receiving/IncomingGroupsV2MessageJob+SDS.swift +++ b/SignalServiceKit/src/Network/Receiving/IncomingGroupsV2MessageJob+SDS.swift @@ -393,8 +393,6 @@ public extension IncomingGroupsV2MessageJob { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return IncomingGroupsV2MessageJob.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(IncomingGroupsV2MessageJobRecord.databaseTableName) WHERE \(incomingGroupsV2MessageJobColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -425,14 +423,6 @@ public extension IncomingGroupsV2MessageJob { batchSize: UInt, block: @escaping (IncomingGroupsV2MessageJob, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - IncomingGroupsV2MessageJob.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? IncomingGroupsV2MessageJob else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = IncomingGroupsV2MessageJob.grdbFetchCursor(transaction: grdbTransaction) @@ -474,10 +464,6 @@ public extension IncomingGroupsV2MessageJob { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: IncomingGroupsV2MessageJob.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -509,8 +495,6 @@ public extension IncomingGroupsV2MessageJob { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: IncomingGroupsV2MessageJob.collection()) case .grdbRead(let grdbTransaction): return IncomingGroupsV2MessageJobRecord.ows_fetchCount(grdbTransaction.database) } @@ -520,8 +504,6 @@ public extension IncomingGroupsV2MessageJob { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: IncomingGroupsV2MessageJob.collection()) case .grdbWrite(let grdbTransaction): do { try IncomingGroupsV2MessageJobRecord.deleteAll(grdbTransaction.database) @@ -570,8 +552,6 @@ public extension IncomingGroupsV2MessageJob { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: IncomingGroupsV2MessageJob.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(IncomingGroupsV2MessageJobRecord.databaseTableName) WHERE \(incomingGroupsV2MessageJobColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Network/Receiving/MessageContentJobFinder.swift b/SignalServiceKit/src/Network/Receiving/MessageContentJobFinder.swift index 31d844a0d5..3d54fc46ac 100644 --- a/SignalServiceKit/src/Network/Receiving/MessageContentJobFinder.swift +++ b/SignalServiceKit/src/Network/Receiving/MessageContentJobFinder.swift @@ -20,14 +20,11 @@ public class AnyMessageContentJobFinder: NSObject, MessageContentJobFinder { typealias ReadTransaction = SDSAnyReadTransaction typealias WriteTransaction = SDSAnyWriteTransaction - let yapAdapter = YAPDBMessageContentJobFinder() let grdbAdapter = GRDBMessageContentJobFinder() @objc public func addJob(envelopeData: Data, plaintextData: Data?, wasReceivedByUD: Bool, serverDeliveryTimestamp: UInt64, transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let yapWrite): - yapAdapter.addJob(withEnvelopeData: envelopeData, plaintextData: plaintextData, wasReceivedByUD: wasReceivedByUD, serverDeliveryTimestamp: serverDeliveryTimestamp, transaction: yapWrite) case .grdbWrite(let grdbWrite): grdbAdapter.addJob(envelopeData: envelopeData, plaintextData: plaintextData, wasReceivedByUD: wasReceivedByUD, serverDeliveryTimestamp: serverDeliveryTimestamp, transaction: grdbWrite) } @@ -36,8 +33,6 @@ public class AnyMessageContentJobFinder: NSObject, MessageContentJobFinder { @objc public func nextJobs(batchSize: UInt, transaction: SDSAnyReadTransaction) -> [OWSMessageContentJob] { switch transaction.readTransaction { - case .yapRead(let yapRead): - return yapAdapter.nextJobs(forBatchSize: batchSize, transaction: yapRead) case .grdbRead(let grdbRead): return grdbAdapter.nextJobs(batchSize: batchSize, transaction: grdbRead) } @@ -45,8 +40,6 @@ public class AnyMessageContentJobFinder: NSObject, MessageContentJobFinder { @objc func allJobs(transaction: SDSAnyReadTransaction) -> [OWSMessageContentJob] { switch transaction.readTransaction { - case .yapRead(let yapRead): - owsFail("YAP not supported") case .grdbRead(let grdbRead): return grdbAdapter.allJobs(transaction: grdbRead) } @@ -55,8 +48,6 @@ public class AnyMessageContentJobFinder: NSObject, MessageContentJobFinder { @objc public func removeJobs(withUniqueIds uniqueIds: [String], transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let yapWrite): - yapAdapter.removeJobs(withIds: uniqueIds, transaction: yapWrite) case .grdbWrite(let grdbWrite): grdbAdapter.removeJobs(withUniqueIds: uniqueIds, transaction: grdbWrite) } diff --git a/SignalServiceKit/src/Network/Receiving/YAPDBMessageContentJobFinder.h b/SignalServiceKit/src/Network/Receiving/YAPDBMessageContentJobFinder.h deleted file mode 100644 index 7da385148f..0000000000 --- a/SignalServiceKit/src/Network/Receiving/YAPDBMessageContentJobFinder.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSMessageContentJob; -@class OWSStorage; -@class YapDatabaseReadTransaction; -@class YapDatabaseReadWriteTransaction; - -@interface YAPDBMessageContentJobFinder : NSObject - -- (NSArray *)nextJobsForBatchSize:(NSUInteger)maxBatchSize - transaction:(YapDatabaseReadTransaction *)transaction; - -- (void)addJobWithEnvelopeData:(NSData *)envelopeData - plaintextData:(NSData *_Nullable)plaintextData - wasReceivedByUD:(BOOL)wasReceivedByUD - serverDeliveryTimestamp:(uint64_t)serverDeliveryTimestamp - transaction:(YapDatabaseReadWriteTransaction *)transaction; - -- (void)removeJobsWithIds:(NSArray *)uniqueIds transaction:(YapDatabaseReadWriteTransaction *)transaction; - -+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Network/Receiving/YAPDBMessageContentJobFinder.m b/SignalServiceKit/src/Network/Receiving/YAPDBMessageContentJobFinder.m deleted file mode 100644 index 7b4f5250c4..0000000000 --- a/SignalServiceKit/src/Network/Receiving/YAPDBMessageContentJobFinder.m +++ /dev/null @@ -1,122 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import "YAPDBMessageContentJobFinder.h" -#import "OWSStorage.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -NSString *const YAPDBMessageContentJobFinderExtensionName = @"OWSMessageContentJobFinderExtensionName2"; -NSString *const YAPDBMessageContentJobFinderExtensionGroup = @"OWSMessageContentJobFinderExtensionGroup2"; - -@implementation YAPDBMessageContentJobFinder - -- (NSArray *)nextJobsForBatchSize:(NSUInteger)maxBatchSize - transaction:(YapDatabaseReadTransaction *)transaction -{ - NSMutableArray *jobs = [NSMutableArray new]; - YapDatabaseViewTransaction *viewTransaction = [transaction ext:YAPDBMessageContentJobFinderExtensionName]; - OWSAssertDebug(viewTransaction != nil); - [viewTransaction enumerateKeysAndObjectsInGroup:YAPDBMessageContentJobFinderExtensionGroup - usingBlock:^(NSString *_Nonnull collection, - NSString *_Nonnull key, - id _Nonnull object, - NSUInteger index, - BOOL *_Nonnull stop) { - OWSMessageContentJob *job = object; - [jobs addObject:job]; - if (jobs.count >= maxBatchSize) { - *stop = YES; - } - }]; - - return [jobs copy]; -} - -- (void)addJobWithEnvelopeData:(NSData *)envelopeData - plaintextData:(NSData *_Nullable)plaintextData - wasReceivedByUD:(BOOL)wasReceivedByUD - serverDeliveryTimestamp:(uint64_t)serverDeliveryTimestamp - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(envelopeData); - OWSAssertDebug(transaction); - - OWSMessageContentJob *job = [[OWSMessageContentJob alloc] initWithEnvelopeData:envelopeData - plaintextData:plaintextData - wasReceivedByUD:wasReceivedByUD - serverDeliveryTimestamp:serverDeliveryTimestamp]; - [job anyInsertWithTransaction:transaction.asAnyWrite]; -} - -- (void)removeJobsWithIds:(NSArray *)uniqueIds transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - [transaction removeObjectsForKeys:uniqueIds inCollection:[OWSMessageContentJob collection]]; -} - -+ (YapDatabaseView *)databaseExtension -{ - YapDatabaseViewSorting *sorting = - [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction, - NSString *group, - NSString *collection1, - NSString *key1, - id object1, - NSString *collection2, - NSString *key2, - id object2) { - if (![object1 isKindOfClass:[OWSMessageContentJob class]]) { - OWSFailDebug(@"Unexpected object: %@ in collection: %@", [object1 class], collection1); - return NSOrderedSame; - } - OWSMessageContentJob *job1 = (OWSMessageContentJob *)object1; - - if (![object2 isKindOfClass:[OWSMessageContentJob class]]) { - OWSFailDebug(@"Unexpected object: %@ in collection: %@", [object2 class], collection2); - return NSOrderedSame; - } - OWSMessageContentJob *job2 = (OWSMessageContentJob *)object2; - - return [job1.createdAt compare:job2.createdAt]; - }]; - - YapDatabaseViewGrouping *grouping = - [YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable(YapDatabaseReadTransaction *_Nonnull transaction, - NSString *_Nonnull collection, - NSString *_Nonnull key, - id _Nonnull object) { - if (![object isKindOfClass:[OWSMessageContentJob class]]) { - OWSFailDebug(@"Unexpected object: %@ in collection: %@", object, collection); - return nil; - } - - // Arbitrary string - all in the same group. We're only using the view for sorting. - return YAPDBMessageContentJobFinderExtensionGroup; - }]; - - YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; - options.allowedCollections = - [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[OWSMessageContentJob collection]]]; - - return [[YapDatabaseAutoView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"1" options:options]; -} - -+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage -{ - YapDatabaseView *existingView = [storage registeredExtension:YAPDBMessageContentJobFinderExtensionName]; - if (existingView) { - OWSFailDebug(@"%@ was already initialized.", YAPDBMessageContentJobFinderExtensionName); - // already initialized - return; - } - [storage asyncRegisterExtension:[self databaseExtension] withName:YAPDBMessageContentJobFinderExtensionName]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/SSKEnvironment.h b/SignalServiceKit/src/SSKEnvironment.h index 6ee29540c2..affb215d90 100644 --- a/SignalServiceKit/src/SSKEnvironment.h +++ b/SignalServiceKit/src/SSKEnvironment.h @@ -25,7 +25,6 @@ NS_ASSUME_NONNULL_BEGIN @class OWSMessageManager; @class OWSMessagePipelineSupervisor; @class OWSOutgoingReceiptManager; -@class OWSPrimaryStorage; @class OWSReadReceiptManager; @class SDSDatabaseStorage; @class SSKPreKeyStore; @@ -38,7 +37,6 @@ NS_ASSUME_NONNULL_BEGIN @class TSAccountManager; @class TSNetworkManager; @class TSSocketManager; -@class YapDatabaseConnection; @protocol ContactsManagerProtocol; @protocol NotificationsProtocol; @@ -66,7 +64,6 @@ NS_ASSUME_NONNULL_BEGIN messageSenderJobQueue:(MessageSenderJobQueue *)messageSenderJobQueue pendingReadReceiptRecorder:(id)pendingReadReceiptRecorder profileManager:(id)profileManager - primaryStorage:(nullable OWSPrimaryStorage *)primaryStorage networkManager:(TSNetworkManager *)networkManager messageManager:(OWSMessageManager *)messageManager blockingManager:(OWSBlockingManager *)blockingManager @@ -164,15 +161,11 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) AppExpiry *appExpiryRef; @property (nonatomic, readonly) MessageProcessor *messageProcessorRef; -@property (nonatomic, readonly, nullable) OWSPrimaryStorage *primaryStorageRef; - // This property is configured after Environment is created. @property (atomic, nullable) id callMessageHandlerRef; // This property is configured after Environment is created. @property (atomic, nullable) id notificationsManagerRef; -@property (atomic, readonly) YapDatabaseConnection *migrationDBConnection; - - (BOOL)isComplete; - (void)warmCaches; diff --git a/SignalServiceKit/src/SSKEnvironment.m b/SignalServiceKit/src/SSKEnvironment.m index a6afe57fca..3b153bdb54 100644 --- a/SignalServiceKit/src/SSKEnvironment.m +++ b/SignalServiceKit/src/SSKEnvironment.m @@ -5,7 +5,6 @@ #import "SSKEnvironment.h" #import "AppContext.h" #import "OWSBlockingManager.h" -#import "OWSPrimaryStorage.h" #import "TSAccountManager.h" #import #import @@ -19,7 +18,6 @@ static SSKEnvironment *sharedSSKEnvironment; @property (nonatomic) id contactsManagerRef; @property (nonatomic) MessageSender *messageSenderRef; @property (nonatomic) id profileManagerRef; -@property (nonatomic, nullable) OWSPrimaryStorage *primaryStorageRef; @property (nonatomic) TSNetworkManager *networkManagerRef; @property (nonatomic) OWSMessageManager *messageManagerRef; @property (nonatomic) OWSBlockingManager *blockingManagerRef; @@ -61,7 +59,6 @@ static SSKEnvironment *sharedSSKEnvironment; @synthesize callMessageHandlerRef = _callMessageHandlerRef; @synthesize notificationsManagerRef = _notificationsManagerRef; -@synthesize migrationDBConnection = _migrationDBConnection; - (instancetype)initWithContactsManager:(id)contactsManager linkPreviewManager:(OWSLinkPreviewManager *)linkPreviewManager @@ -69,7 +66,6 @@ static SSKEnvironment *sharedSSKEnvironment; messageSenderJobQueue:(MessageSenderJobQueue *)messageSenderJobQueue pendingReadReceiptRecorder:(id)pendingReadReceiptRecorder profileManager:(id)profileManager - primaryStorage:(nullable OWSPrimaryStorage *)primaryStorage networkManager:(TSNetworkManager *)networkManager messageManager:(OWSMessageManager *)messageManager blockingManager:(OWSBlockingManager *)blockingManager @@ -121,7 +117,6 @@ static SSKEnvironment *sharedSSKEnvironment; _messageSenderJobQueueRef = messageSenderJobQueue; _pendingReadReceiptRecorderRef = pendingReadReceiptRecorder; _profileManagerRef = profileManager; - _primaryStorageRef = primaryStorage; _networkManagerRef = networkManager; _messageManagerRef = messageManager; _blockingManagerRef = blockingManager; @@ -235,25 +230,8 @@ static SSKEnvironment *sharedSSKEnvironment; return (self.callMessageHandler != nil && self.notificationsManager != nil); } -- (YapDatabaseConnection *)migrationDBConnection -{ - OWSAssert(self.primaryStorage); - - @synchronized(self) { - if (!_migrationDBConnection) { - _migrationDBConnection = self.primaryStorage.newDatabaseConnection; - } - return _migrationDBConnection; - } -} - - (void)warmCaches { - // Pre-heat caches to avoid sneaky transactions during the YDB->GRDB migrations. - // We need to warm these caches _before_ the migrations run. - // - // We need to do as few writes as possible here, to avoid conflicts - // with the migrations which haven't run yet. [self.tsAccountManager warmCaches]; [self.signalServiceAddressCache warmCaches]; [self.remoteConfigManager warmCaches]; diff --git a/SignalServiceKit/src/Security/OWSRecipientIdentity+SDS.swift b/SignalServiceKit/src/Security/OWSRecipientIdentity+SDS.swift index e9baecaeaa..ed28c4f244 100644 --- a/SignalServiceKit/src/Security/OWSRecipientIdentity+SDS.swift +++ b/SignalServiceKit/src/Security/OWSRecipientIdentity+SDS.swift @@ -384,8 +384,6 @@ public extension OWSRecipientIdentity { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return OWSRecipientIdentity.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(RecipientIdentityRecord.databaseTableName) WHERE \(recipientIdentityColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -416,14 +414,6 @@ public extension OWSRecipientIdentity { batchSize: UInt, block: @escaping (OWSRecipientIdentity, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - OWSRecipientIdentity.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? OWSRecipientIdentity else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = OWSRecipientIdentity.grdbFetchCursor(transaction: grdbTransaction) @@ -465,10 +455,6 @@ public extension OWSRecipientIdentity { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: OWSRecipientIdentity.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -500,8 +486,6 @@ public extension OWSRecipientIdentity { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: OWSRecipientIdentity.collection()) case .grdbRead(let grdbTransaction): return RecipientIdentityRecord.ows_fetchCount(grdbTransaction.database) } @@ -511,8 +495,6 @@ public extension OWSRecipientIdentity { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: OWSRecipientIdentity.collection()) case .grdbWrite(let grdbTransaction): do { try RecipientIdentityRecord.deleteAll(grdbTransaction.database) @@ -561,8 +543,6 @@ public extension OWSRecipientIdentity { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: OWSRecipientIdentity.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(RecipientIdentityRecord.databaseTableName) WHERE \(recipientIdentityColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/SignalServiceKit.h b/SignalServiceKit/src/SignalServiceKit.h index f9c049cce2..9a53030fa3 100644 --- a/SignalServiceKit/src/SignalServiceKit.h +++ b/SignalServiceKit/src/SignalServiceKit.h @@ -38,7 +38,6 @@ #import #import #import -#import #import #import #import @@ -84,4 +83,3 @@ #import #import #import -#import diff --git a/SignalServiceKit/src/Storage/Database/GRDBDatabaseStorageAdapter.swift b/SignalServiceKit/src/Storage/Database/GRDBDatabaseStorageAdapter.swift index dfe78be48b..6b9ecfefb5 100644 --- a/SignalServiceKit/src/Storage/Database/GRDBDatabaseStorageAdapter.swift +++ b/SignalServiceKit/src/Storage/Database/GRDBDatabaseStorageAdapter.swift @@ -8,6 +8,9 @@ import GRDB @objc public class GRDBDatabaseStorageAdapter: NSObject { + // 256 bit key + 128 bit salt + public static let kSQLCipherKeySpecLength: UInt = 48 + static func databaseDirUrl(baseDir: URL) -> URL { return baseDir.appendingPathComponent("grdb", isDirectory: true) } @@ -199,7 +202,6 @@ public class GRDBDatabaseStorageAdapter: NSObject { // // * This is a new install so there's no existing password to retrieve. // * The keychain has become corrupt. - // * We are about to do a ydb-to-grdb migration. let databaseUrl = GRDBDatabaseStorageAdapter.databaseFileUrl(baseDir: baseDir) let doesDBExist = FileManager.default.fileExists(atPath: databaseUrl.path) if doesDBExist { @@ -257,28 +259,8 @@ extension GRDBDatabaseStorageAdapter: SDSDatabaseStorageAdapter { } #endif - private func assertCanRead() { - if !databaseStorage.canReadFromGrdb { - Logger.error("storageMode: \(FeatureFlags.storageModeDescription).") - Logger.error( - "StorageCoordinatorState: \(NSStringFromStorageCoordinatorState(storageCoordinator.state)).") - Logger.error( - "dataStoreForUI: \(NSStringForDataStore(StorageCoordinator.dataStoreForUI)).") - - switch FeatureFlags.storageModeStrictness { - case .fail: - owsFail("Unexpected GRDB read.") - case .failDebug: - owsFailDebug("Unexpected GRDB read.") - case .log: - Logger.error("Unexpected GRDB read.") - } - } - } - // TODO readThrows/writeThrows flavors public func uiReadThrows(block: (GRDBReadTransaction) throws -> Void) rethrows { - assertCanRead() #if TESTABLE_BUILD owsAssertDebug(Self.canOpenTransaction) @@ -304,7 +286,6 @@ extension GRDBDatabaseStorageAdapter: SDSDatabaseStorageAdapter { @discardableResult public func read(block: (GRDBReadTransaction) throws -> T) throws -> T { - assertCanRead() #if TESTABLE_BUILD owsAssertDebug(Self.canOpenTransaction) @@ -347,7 +328,6 @@ extension GRDBDatabaseStorageAdapter: SDSDatabaseStorageAdapter { @objc public func uiRead(block: (GRDBReadTransaction) -> Void) throws { - assertCanRead() AssertIsOnMainThread() #if TESTABLE_BUILD @@ -378,7 +358,6 @@ extension GRDBDatabaseStorageAdapter: SDSDatabaseStorageAdapter { @objc public func read(block: (GRDBReadTransaction) -> Void) throws { - assertCanRead() #if TESTABLE_BUILD owsAssertDebug(Self.canOpenTransaction) @@ -400,28 +379,8 @@ extension GRDBDatabaseStorageAdapter: SDSDatabaseStorageAdapter { } } - private func assertCanWrite() { - if !databaseStorage.canWriteToGrdb { - Logger.error("storageMode: \(FeatureFlags.storageModeDescription).") - Logger.error( - "StorageCoordinatorState: \(NSStringFromStorageCoordinatorState(storageCoordinator.state)).") - Logger.error( - "dataStoreForUI: \(NSStringForDataStore(StorageCoordinator.dataStoreForUI)).") - - switch FeatureFlags.storageModeStrictness { - case .fail: - owsFail("Unexpected GRDB write.") - case .failDebug: - owsFailDebug("Unexpected GRDB write.") - case .log: - Logger.error("Unexpected GRDB write.") - } - } - } - @objc public func write(block: (GRDBWriteTransaction) -> Void) throws { - assertCanWrite() #if TESTABLE_BUILD owsAssertDebug(Self.canOpenTransaction) @@ -566,8 +525,10 @@ private struct GRDBStorage { // MARK: - public struct GRDBKeySpecSource { - // 256 bit key + 128 bit salt - private let kSQLCipherKeySpecLength: UInt = 48 + + private var kSQLCipherKeySpecLength: UInt { + GRDBDatabaseStorageAdapter.kSQLCipherKeySpecLength + } let keyServiceName: String let keyName: String diff --git a/SignalServiceKit/src/Storage/Database/Records/AttachmentFinder.swift b/SignalServiceKit/src/Storage/Database/Records/AttachmentFinder.swift index 33940f8f8b..b5138f7ab4 100644 --- a/SignalServiceKit/src/Storage/Database/Records/AttachmentFinder.swift +++ b/SignalServiceKit/src/Storage/Database/Records/AttachmentFinder.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // import Foundation @@ -18,12 +18,10 @@ protocol AttachmentFinderAdapter { @objc public class AttachmentFinder: NSObject, AttachmentFinderAdapter { - let yapAdapter: YAPDBAttachmentFinderAdapter let grdbAdapter: GRDBAttachmentFinderAdapter @objc public init(threadUniqueId: String) { - self.yapAdapter = YAPDBAttachmentFinderAdapter(threadUniqueId: threadUniqueId) self.grdbAdapter = GRDBAttachmentFinderAdapter(threadUniqueId: threadUniqueId) } @@ -32,8 +30,6 @@ public class AttachmentFinder: NSObject, AttachmentFinderAdapter { @objc public class func unfailedAttachmentPointerIds(transaction: SDSAnyReadTransaction) -> [String] { switch transaction.readTransaction { - case .yapRead(let yapRead): - return YAPDBAttachmentFinderAdapter.unfailedAttachmentPointerIds(transaction: yapRead) case .grdbRead(let grdbRead): return GRDBAttachmentFinderAdapter.unfailedAttachmentPointerIds(transaction: grdbRead) } @@ -42,8 +38,6 @@ public class AttachmentFinder: NSObject, AttachmentFinderAdapter { @objc public class func enumerateAttachmentPointersWithLazyRestoreFragments(transaction: SDSAnyReadTransaction, block: @escaping (TSAttachmentPointer, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let yapRead): - return YAPDBAttachmentFinderAdapter.enumerateAttachmentPointersWithLazyRestoreFragments(transaction: yapRead, block: block) case .grdbRead(let grdbRead): return GRDBAttachmentFinderAdapter.enumerateAttachmentPointersWithLazyRestoreFragments(transaction: grdbRead, block: block) } @@ -114,40 +108,6 @@ public class AttachmentFinder: NSObject, AttachmentFinderAdapter { // MARK: - -// GRDB TODO: Nice to have: pull all of the YDB finder logic into this file. -struct YAPDBAttachmentFinderAdapter: AttachmentFinderAdapter { - - private let threadUniqueId: String - - init(threadUniqueId: String) { - self.threadUniqueId = threadUniqueId - } - - // MARK: - static methods - - static func unfailedAttachmentPointerIds(transaction: YapDatabaseReadTransaction) -> [String] { - return OWSFailedAttachmentDownloadsJob.unfailedAttachmentPointerIds(with: transaction) - } - - static func enumerateAttachmentPointersWithLazyRestoreFragments(transaction: YapDatabaseReadTransaction, block: @escaping (TSAttachmentPointer, UnsafeMutablePointer) -> Void) { - guard let view = transaction.safeViewTransaction(TSLazyRestoreAttachmentsDatabaseViewExtensionName) else { - owsFailDebug("Could not load view transaction.") - return - } - - view.safe_enumerateKeysAndObjects(inGroup: TSLazyRestoreAttachmentsGroup, - extensionName: TSLazyRestoreAttachmentsDatabaseViewExtensionName) { (_, _, object, _, stopPtr) in - guard let job = object as? TSAttachmentPointer else { - owsFailDebug("unexpected job: \(type(of: object))") - return - } - block(job, stopPtr) - } - } -} - -// MARK: - - struct GRDBAttachmentFinderAdapter: AttachmentFinderAdapter { typealias ReadTransaction = GRDBReadTransaction diff --git a/SignalServiceKit/src/Storage/Database/Records/InteractionFinder.swift b/SignalServiceKit/src/Storage/Database/Records/InteractionFinder.swift index a52e530766..e6b259d01d 100644 --- a/SignalServiceKit/src/Storage/Database/Records/InteractionFinder.swift +++ b/SignalServiceKit/src/Storage/Database/Records/InteractionFinder.swift @@ -58,14 +58,12 @@ protocol InteractionFinderAdapter { @objc public class InteractionFinder: NSObject, InteractionFinderAdapter { - let yapAdapter: YAPDBInteractionFinderAdapter let grdbAdapter: GRDBInteractionFinder let threadUniqueId: String @objc public init(threadUniqueId: String) { self.threadUniqueId = threadUniqueId - self.yapAdapter = YAPDBInteractionFinderAdapter(threadUniqueId: threadUniqueId) self.grdbAdapter = GRDBInteractionFinder(threadUniqueId: threadUniqueId) } @@ -83,8 +81,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { public class func fetch(uniqueId: String, transaction: SDSAnyReadTransaction) throws -> TSInteraction? { switch transaction.readTransaction { - case .yapRead(let yapRead): - return YAPDBInteractionFinderAdapter.fetch(uniqueId: uniqueId, transaction: yapRead) case .grdbRead(let grdbRead): return try GRDBInteractionFinder.fetch(uniqueId: uniqueId, transaction: grdbRead) } @@ -93,8 +89,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public class func existsIncomingMessage(timestamp: UInt64, address: SignalServiceAddress, sourceDeviceId: UInt32, transaction: SDSAnyReadTransaction) -> Bool { switch transaction.readTransaction { - case .yapRead(let yapRead): - return YAPDBInteractionFinderAdapter.existsIncomingMessage(timestamp: timestamp, address: address, sourceDeviceId: sourceDeviceId, transaction: yapRead) case .grdbRead(let grdbRead): return GRDBInteractionFinder.existsIncomingMessage(timestamp: timestamp, address: address, sourceDeviceId: sourceDeviceId, transaction: grdbRead) } @@ -103,10 +97,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public class func interactions(withTimestamp timestamp: UInt64, filter: @escaping (TSInteraction) -> Bool, transaction: SDSAnyReadTransaction) throws -> [TSInteraction] { switch transaction.readTransaction { - case .yapRead(let yapRead): - return try YAPDBInteractionFinderAdapter.interactions(withTimestamp: timestamp, - filter: filter, - transaction: yapRead) case .grdbRead(let grdbRead): return try GRDBInteractionFinder.interactions(withTimestamp: timestamp, filter: filter, @@ -117,8 +107,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public class func incompleteCallIds(transaction: SDSAnyReadTransaction) -> [String] { switch transaction.readTransaction { - case .yapRead(let yapRead): - return YAPDBInteractionFinderAdapter.incompleteCallIds(transaction: yapRead) case .grdbRead(let grdbRead): return GRDBInteractionFinder.incompleteCallIds(transaction: grdbRead) } @@ -127,8 +115,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public class func attemptingOutInteractionIds(transaction: SDSAnyReadTransaction) -> [String] { switch transaction.readTransaction { - case .yapRead(let yapRead): - return YAPDBInteractionFinderAdapter.attemptingOutInteractionIds(transaction: yapRead) case .grdbRead(let grdbRead): return GRDBInteractionFinder.attemptingOutInteractionIds(transaction: grdbRead) } @@ -176,8 +162,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public class func enumerateMessagesWithStartedPerConversationExpiration(transaction: SDSAnyReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let yapRead): - YAPDBInteractionFinderAdapter.enumerateMessagesWithStartedPerConversationExpiration(transaction: yapRead, block: block) case .grdbRead(let grdbRead): GRDBInteractionFinder.enumerateMessagesWithStartedPerConversationExpiration(transaction: grdbRead, block: block) } @@ -186,8 +170,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public class func interactionIdsWithExpiredPerConversationExpiration(transaction: SDSAnyReadTransaction) -> [String] { switch transaction.readTransaction { - case .yapRead(let yapRead): - return YAPDBInteractionFinderAdapter.interactionIdsWithExpiredPerConversationExpiration(transaction: yapRead) case .grdbRead(let grdbRead): return GRDBInteractionFinder.interactionIdsWithExpiredPerConversationExpiration(transaction: grdbRead) } @@ -196,8 +178,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public class func enumerateMessagesWhichFailedToStartExpiring(transaction: SDSAnyReadTransaction, block: @escaping (TSMessage, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let yapRead): - YAPDBInteractionFinderAdapter.enumerateMessagesWhichFailedToStartExpiring(transaction: yapRead, block: block) case .grdbRead(let grdbRead): GRDBInteractionFinder.enumerateMessagesWhichFailedToStartExpiring(transaction: grdbRead, block: block) } @@ -206,8 +186,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public class func interactions(withInteractionIds interactionIds: Set, transaction: SDSAnyReadTransaction) -> Set { switch transaction.readTransaction { - case .yapRead(let yapRead): - return YAPDBInteractionFinderAdapter.interactions(withInteractionIds: interactionIds, transaction: yapRead) case .grdbRead(let grdbRead): return GRDBInteractionFinder.interactions(withInteractionIds: interactionIds, transaction: grdbRead) } @@ -275,8 +253,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc func mostRecentInteractionForInbox(transaction: SDSAnyReadTransaction) -> TSInteraction? { switch transaction.readTransaction { - case .yapRead(let yapRead): - return yapAdapter.mostRecentInteractionForInbox(transaction: yapRead) case .grdbRead(let grdbRead): return grdbAdapter.mostRecentInteractionForInbox(transaction: grdbRead) } @@ -284,8 +260,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { func earliestKnownInteractionRowId(transaction: SDSAnyReadTransaction) -> Int? { switch transaction.readTransaction { - case .yapRead(let yapRead): - return yapAdapter.earliestKnownInteractionRowId(transaction: yapRead) case .grdbRead(let grdbRead): return grdbAdapter.earliestKnownInteractionRowId(transaction: grdbRead) } @@ -294,8 +268,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { public func distanceFromLatest(interactionUniqueId: String, transaction: SDSAnyReadTransaction) throws -> UInt? { return try Bench(title: "InteractionFinder.distanceFromLatest") { switch transaction.readTransaction { - case .yapRead(let yapRead): - return yapAdapter.distanceFromLatest(interactionUniqueId: interactionUniqueId, transaction: yapRead) case .grdbRead(let grdbRead): return try grdbAdapter.distanceFromLatest(interactionUniqueId: interactionUniqueId, transaction: grdbRead) } @@ -305,8 +277,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public func count(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let yapRead): - return yapAdapter.count(transaction: yapRead) case .grdbRead(let grdbRead): return grdbAdapter.count(transaction: grdbRead) } @@ -338,8 +308,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { public func enumerateInteractionIds(transaction: SDSAnyReadTransaction, block: @escaping (String, UnsafeMutablePointer) throws -> Void) throws { switch transaction.readTransaction { - case .yapRead(let yapRead): - return try yapAdapter.enumerateInteractionIds(transaction: yapRead, block: block) case .grdbRead(let grdbRead): return try grdbAdapter.enumerateInteractionIds(transaction: grdbRead, block: block) } @@ -348,8 +316,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public func enumerateInteractionIds(transaction: SDSAnyReadTransaction, block: @escaping (String, UnsafeMutablePointer) -> Void) throws { switch transaction.readTransaction { - case .yapRead(let yapRead): - return try yapAdapter.enumerateInteractionIds(transaction: yapRead, block: block) case .grdbRead(let grdbRead): return try grdbAdapter.enumerateInteractionIds(transaction: grdbRead, block: block) } @@ -358,8 +324,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public func enumerateRecentInteractions(transaction: SDSAnyReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer) -> Void) throws { switch transaction.readTransaction { - case .yapRead(let yapRead): - return try yapAdapter.enumerateRecentInteractions(transaction: yapRead, block: block) case .grdbRead(let grdbRead): return try grdbAdapter.enumerateRecentInteractions(transaction: grdbRead, block: block) } @@ -367,8 +331,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { public func enumerateInteractions(range: NSRange, transaction: SDSAnyReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer) -> Void) throws { switch transaction.readTransaction { - case .yapRead(let yapRead): - return yapAdapter.enumerateInteractions(range: range, transaction: yapRead, block: block) case .grdbRead(let grdbRead): return try grdbAdapter.enumerateInteractions(range: range, transaction: grdbRead, block: block) } @@ -376,9 +338,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { public func interactionIds(inRange range: NSRange, transaction: SDSAnyReadTransaction) throws -> [String] { switch transaction.readTransaction { - case .yapRead(let yapRead): - owsFailDebug("Invalid transaction.") - return try yapAdapter.interactionIds(inRange: range, transaction: yapRead) case .grdbRead(let grdbRead): return try grdbAdapter.interactionIds(inRange: range, transaction: grdbRead) } @@ -500,8 +459,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { public func interaction(at index: UInt, transaction: SDSAnyReadTransaction) throws -> TSInteraction? { switch transaction.readTransaction { - case .yapRead(let yapRead): - return yapAdapter.interaction(at: index, transaction: yapRead) case .grdbRead(let grdbRead): return try grdbAdapter.interaction(at: index, transaction: grdbRead) } @@ -510,8 +467,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public func firstInteraction(atOrAroundSortId sortId: UInt64, transaction: SDSAnyReadTransaction) -> TSInteraction? { switch transaction.readTransaction { - case .yapRead: - fatalError("YAP not supported") case .grdbRead(let grdbRead): return grdbAdapter.firstInteraction(atOrAroundSortId: sortId, transaction: grdbRead) } @@ -520,8 +475,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public func existsOutgoingMessage(transaction: SDSAnyReadTransaction) -> Bool { switch transaction.readTransaction { - case .yapRead(let yapRead): - return yapAdapter.existsOutgoingMessage(transaction: yapRead) case .grdbRead(let grdbRead): return grdbAdapter.existsOutgoingMessage(transaction: grdbRead) } @@ -531,8 +484,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public func enumerateUnstartedExpiringMessages(transaction: SDSAnyReadTransaction, block: @escaping (TSMessage, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let yapRead): - return yapAdapter.enumerateUnstartedExpiringMessages(transaction: yapRead, block: block) case .grdbRead(let grdbRead): return grdbAdapter.enumerateUnstartedExpiringMessages(transaction: grdbRead, block: block) } @@ -542,8 +493,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { @objc public func outgoingMessageCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let yapRead): - return yapAdapter.outgoingMessageCount(transaction: yapRead) case .grdbRead(let grdbRead): return grdbAdapter.outgoingMessageCount(transaction: grdbRead) } @@ -609,217 +558,6 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter { // MARK: - -// GRDB TODO: Nice to have: pull all of the YDB finder logic into this file. -struct YAPDBInteractionFinderAdapter: InteractionFinderAdapter { - - private let threadUniqueId: String - - init(threadUniqueId: String) { - self.threadUniqueId = threadUniqueId - } - - // MARK: - static methods - - static func fetch(uniqueId: String, transaction: YapDatabaseReadTransaction) -> TSInteraction? { - return transaction.object(forKey: uniqueId, inCollection: TSInteraction.collection()) as? TSInteraction - } - - static func existsIncomingMessage(timestamp: UInt64, address: SignalServiceAddress, sourceDeviceId: UInt32, transaction: YapDatabaseReadTransaction) -> Bool { - return OWSIncomingMessageFinder().existsMessage(withTimestamp: timestamp, address: address, sourceDeviceId: sourceDeviceId, transaction: transaction) - } - - static func incompleteCallIds(transaction: YapDatabaseReadTransaction) -> [String] { - return OWSIncompleteCallsJob.ydb_incompleteCallIds(with: transaction) - } - - static func attemptingOutInteractionIds(transaction: YapDatabaseReadTransaction) -> [String] { - return OWSFailedMessagesJob.attemptingOutMessageIds(with: transaction) - } - - static func interactions(withTimestamp timestamp: UInt64, filter: @escaping (TSInteraction) -> Bool, transaction: YapDatabaseReadTransaction) throws -> [TSInteraction] { - return TSInteraction.ydb_interactions(withTimestamp: timestamp, - filter: filter, - with: transaction) - } - - // The interactions should be enumerated in order from "next to expire" to "last to expire". - static func enumerateMessagesWithStartedPerConversationExpiration(transaction: YapDatabaseReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer) -> Void) { - OWSDisappearingMessagesFinder.ydb_enumerateMessagesWithStartedPerConversationExpiration(block, transaction: transaction) - } - - static func interactionIdsWithExpiredPerConversationExpiration(transaction: ReadTransaction) -> [String] { - return OWSDisappearingMessagesFinder.ydb_interactionIdsWithExpiredPerConversationExpiration(with: transaction) - } - - static func enumerateMessagesWhichFailedToStartExpiring(transaction: YapDatabaseReadTransaction, block: @escaping (TSMessage, UnsafeMutablePointer) -> Void) { - OWSDisappearingMessagesFinder.ydb_enumerateMessagesWhichFailedToStartExpiring(block, transaction: transaction) - } - - static func interactions(withInteractionIds interactionIds: Set, transaction: YapDatabaseReadTransaction) -> Set { - owsFail("Not implemented.") - } - - // MARK: - instance methods - - func mostRecentInteractionForInbox(transaction: YapDatabaseReadTransaction) -> TSInteraction? { - var last: TSInteraction? - var missedCount: UInt = 0 - guard let view = interactionExt(transaction) else { - return nil - } - view.safe_enumerateKeysAndObjects(inGroup: threadUniqueId, - extensionName: TSMessageDatabaseViewExtensionName, - with: NSEnumerationOptions.reverse) { (_, _, object, _, stopPtr) in - guard let interaction = object as? TSInteraction else { - owsFailDebug("unexpected interaction: \(type(of: object))") - return - } - if interaction.shouldAppearInInbox(transaction: transaction.asAnyRead) { - last = interaction - stopPtr.pointee = true - } - - missedCount += 1 - // For long ignored threads, with lots of SN changes this can get really slow. - // I see this in development because I have a lot of long forgotten threads with - // members who's test devices are constantly reinstalled. We could add a - // purpose-built DB view, but I think in the real world this is rare to be a - // hotspot. - if missedCount > 50 { - Logger.warn("found last interaction for inbox after skipping \(missedCount) items") - } - } - return last - } - - func earliestKnownInteractionRowId(transaction: YapDatabaseReadTransaction) -> Int? { - fatalError("yap not supported") - } - - func count(transaction: YapDatabaseReadTransaction) -> UInt { - guard let view = interactionExt(transaction) else { - return 0 - } - return view.numberOfItems(inGroup: threadUniqueId) - } - - func distanceFromLatest(interactionUniqueId: String, transaction: YapDatabaseReadTransaction) -> UInt? { - owsFailDebug("unsupported transction") - return nil - } - - func enumerateInteractionIds(transaction: YapDatabaseReadTransaction, block: @escaping (String, UnsafeMutablePointer) throws -> Void) throws { - var errorToRaise: Error? - guard let view = interactionExt(transaction) else { - return - } - view.enumerateKeys(inGroup: threadUniqueId, with: NSEnumerationOptions.reverse) { (_, key, _, stopPtr) in - do { - try block(key, stopPtr) - } catch { - // the block parameter is a `throws` block because the GRDB implementation can throw - // we don't expect this with YapDB, though we still try to handle it. - owsFailDebug("unexpected error: \(error)") - stopPtr.pointee = true - errorToRaise = error - } - } - if let errorToRaise = errorToRaise { - throw errorToRaise - } - } - - func enumerateRecentInteractions(transaction: YapDatabaseReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer) -> Void) throws { - guard let view = interactionExt(transaction) else { - return - } - view.safe_enumerateKeysAndObjects(inGroup: threadUniqueId, - extensionName: TSMessageDatabaseViewExtensionName, - with: NSEnumerationOptions.reverse) { (_, _, object, _, stopPtr) in - guard let interaction = object as? TSInteraction else { - owsFailDebug("unexpected interaction: \(type(of: object))") - return - } - block(interaction, stopPtr) - } - } - - func enumerateInteractions(range: NSRange, transaction: YapDatabaseReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer) -> Void) { - guard let view = interactionExt(transaction) else { - return - } - view.enumerateKeysAndObjects(inGroup: threadUniqueId, with: [], range: range) { (_, _, object, _, stopPtr) in - guard let interaction = object as? TSInteraction else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - - block(interaction, stopPtr) - } - } - - public func interactionIds(inRange range: NSRange, transaction: YapDatabaseReadTransaction) throws -> [String] { - owsFailDebug("Invalid transaction.") - return [] - } - - func interaction(at index: UInt, transaction: YapDatabaseReadTransaction) -> TSInteraction? { - guard let view = interactionExt(transaction) else { - return nil - } - guard let obj = view.object(at: index, inGroup: threadUniqueId) else { - return nil - } - - guard let interaction = obj as? TSInteraction else { - owsFailDebug("unexpected interaction: \(type(of: obj))") - return nil - } - - return interaction - } - - func firstInteraction(atOrAroundSortId sortId: UInt64, transaction: YapDatabaseReadTransaction) -> TSInteraction? { - fatalError("YAP not supported") - } - - func existsOutgoingMessage(transaction: YapDatabaseReadTransaction) -> Bool { - guard let dbView = TSDatabaseView.threadOutgoingMessageDatabaseView(transaction) as? YapDatabaseAutoViewTransaction else { - owsFailDebug("unexpected view") - return false - } - return !dbView.isEmptyGroup(threadUniqueId) - } - - #if DEBUG - func enumerateUnstartedExpiringMessages(transaction: YapDatabaseReadTransaction, block: @escaping (TSMessage, UnsafeMutablePointer) -> Void) { - OWSDisappearingMessagesFinder.ydb_enumerateUnstartedExpiringMessages(withThreadId: self.threadUniqueId, - block: block, - transaction: transaction) - } - #endif - - func outgoingMessageCount(transaction: YapDatabaseReadTransaction) -> UInt { - guard let dbView = TSDatabaseView.threadOutgoingMessageDatabaseView(transaction) as? YapDatabaseAutoViewTransaction else { - owsFailDebug("unexpected view") - return 0 - } - return dbView.numberOfItems(inGroup: threadUniqueId) - } - - // MARK: - private - - private var collection: String { - return TSInteraction.collection() - } - - private func interactionExt(_ transaction: YapDatabaseReadTransaction) -> YapDatabaseViewTransaction? { - return transaction.safeViewTransaction(TSMessageDatabaseViewExtensionName) - } -} - -// MARK: - - @objc public class GRDBInteractionFinder: NSObject, InteractionFinderAdapter { diff --git a/SignalServiceKit/src/Storage/Database/Records/ThreadFinder.swift b/SignalServiceKit/src/Storage/Database/Records/ThreadFinder.swift index f9ba5f0e10..27982bd186 100644 --- a/SignalServiceKit/src/Storage/Database/Records/ThreadFinder.swift +++ b/SignalServiceKit/src/Storage/Database/Records/ThreadFinder.swift @@ -20,14 +20,11 @@ public class AnyThreadFinder: NSObject, ThreadFinder { public typealias ReadTransaction = SDSAnyReadTransaction let grdbAdapter: GRDBThreadFinder = GRDBThreadFinder() - let yapAdapter: YAPDBThreadFinder = YAPDBThreadFinder() public func visibleThreadCount(isArchived: Bool, transaction: SDSAnyReadTransaction) throws -> UInt { switch transaction.readTransaction { case .grdbRead(let grdb): return try grdbAdapter.visibleThreadCount(isArchived: isArchived, transaction: grdb) - case .yapRead(let yap): - return yapAdapter.visibleThreadCount(isArchived: isArchived, transaction: yap) } } @@ -36,8 +33,6 @@ public class AnyThreadFinder: NSObject, ThreadFinder { switch transaction.readTransaction { case .grdbRead(let grdb): try grdbAdapter.enumerateVisibleThreads(isArchived: isArchived, transaction: grdb, block: block) - case .yapRead(let yap): - yapAdapter.enumerateVisibleThreads(isArchived: isArchived, transaction: yap, block: block) } } @@ -46,8 +41,6 @@ public class AnyThreadFinder: NSObject, ThreadFinder { switch transaction.readTransaction { case .grdbRead(let grdb): return try grdbAdapter.visibleThreadIds(isArchived: isArchived, transaction: grdb) - case .yapRead(let yap): - return try yapAdapter.visibleThreadIds(isArchived: isArchived, transaction: yap) } } @@ -68,8 +61,6 @@ public class AnyThreadFinder: NSObject, ThreadFinder { switch transaction.readTransaction { case .grdbRead(let grdb): return try grdbAdapter.sortIndex(thread: thread, transaction: grdb) - case .yapRead(let yap): - return yapAdapter.sortIndex(thread: thread, transaction: yap) } } @@ -77,87 +68,11 @@ public class AnyThreadFinder: NSObject, ThreadFinder { switch transaction.readTransaction { case .grdbRead(let grdb): return try grdbAdapter.threads(withThreadIds: threadIds, transaction: grdb) - case .yapRead(let yap): - return try yapAdapter.threads(withThreadIds: threadIds, transaction: yap) } } } -struct YAPDBThreadFinder: ThreadFinder { - typealias ReadTransaction = YapDatabaseReadTransaction - - func visibleThreadCount(isArchived: Bool, transaction: YapDatabaseReadTransaction) -> UInt { - guard let view = ext(transaction) else { - return 0 - } - return view.numberOfItems(inGroup: group(isArchived: isArchived)) - } - - func enumerateVisibleThreads(isArchived: Bool, transaction: YapDatabaseReadTransaction, block: @escaping (TSThread) -> Void) { - guard let view = ext(transaction) else { - return - } - view.safe_enumerateKeysAndObjects(inGroup: group(isArchived: isArchived), - extensionName: type(of: self).extensionName, - with: NSEnumerationOptions.reverse) { _, _, object, _, _ in - guard let thread = object as? TSThread else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(thread) - } - } - - func visibleThreadIds(isArchived: Bool, transaction: YapDatabaseReadTransaction) throws -> [String] { - throw OWSAssertionError("Not implemented.") - } - - func sortIndex(thread: TSThread, transaction: YapDatabaseReadTransaction) -> UInt? { - guard let view = ext(transaction) else { - owsFailDebug("view was unexpectedly nil") - return nil - } - - var index: UInt = 0 - var group: NSString? - let wasFound = view.getGroup(&group, - index: &index, - forKey: thread.uniqueId, - inCollection: TSThread.collection()) - if wasFound, let group = group { - let numberOfItems = view.numberOfItems(inGroup: group as String) - guard numberOfItems > 0 else { - owsFailDebug("numberOfItems <= 0") - return nil - } - // since in yap our Inbox uses reversed sorting, our index must be reversed - let reverseIndex = (Int(numberOfItems) - 1) - Int(index) - guard reverseIndex >= 0 else { - owsFailDebug("reverseIndex was < 0") - return nil - } - return UInt(reverseIndex) - } else { - return nil - } - } - - func threads(withThreadIds threadIds: Set, transaction: YapDatabaseReadTransaction) throws -> Set { - throw OWSAssertionError("Not implemented.") - } - - // MARK: - - - private static let extensionName: String = TSThreadDatabaseViewExtensionName - - private func group(isArchived: Bool) -> String { - return isArchived ? TSArchiveGroup : TSInboxGroup - } - - private func ext(_ transaction: YapDatabaseReadTransaction) -> YapDatabaseViewTransaction? { - return transaction.safeViewTransaction(type(of: self).extensionName) - } -} +// MARK: - @objc public class GRDBThreadFinder: NSObject, ThreadFinder { diff --git a/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift b/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift index 571125a05e..64240ff33c 100644 --- a/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift +++ b/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift @@ -25,23 +25,6 @@ public class SDSDatabaseStorage: SDSTransactable { // MARK: - Initialization / Setup - @objc - public var yapPrimaryStorage: OWSPrimaryStorage { - return yapStorage.storage - } - - private var _yapStorage: YAPDBStorageAdapter? - - var yapStorage: YAPDBStorageAdapter { - if let storage = _yapStorage { - return storage - } else { - let storage = createYapStorage() - _yapStorage = storage - return storage - } - } - private var _grdbStorage: GRDBDatabaseStorageAdapter? @objc @@ -68,10 +51,7 @@ public class SDSDatabaseStorage: SDSTransactable { guard !CurrentAppContext().isRunningTests else { return } - guard StorageCoordinator.dataStoreForUI == .grdb else { - // YDB uses a different mechanism for cross process writes. - return - } + owsAssertDebug(StorageCoordinator.dataStoreForUI == .grdb) // Cross process writes crossProcess.callback = { [weak self] in DispatchQueue.main.async { @@ -90,25 +70,6 @@ public class SDSDatabaseStorage: SDSTransactable { NotificationCenter.default.removeObserver(self) } - // GRDB TODO: Remove - @objc - public static var shouldUseDisposableGrdb: Bool { - // We don't need to use a "disposable" database in our tests; - // TestAppContext ensures that our entire appSharedDataDirectoryPath - // is disposable in that case. - - if .grdbThrowawayIfMigrating == FeatureFlags.storageMode { - // .grdbThrowawayIfMigrating allows us to re-test the migration on each launch. - // It doesn't make sense (and won't work) if there's no YDB database - // to migrate. - // - // Specifically, state persisted in NSUserDefaults won't be "throw away" - // and this will break the app if we throw away our database. - return StorageCoordinator.hasYdbFile - } - return false - } - private class func baseDir() -> URL { return URL(fileURLWithPath: CurrentAppContext().appDatabaseBaseDirectoryPath(), isDirectory: true) @@ -130,8 +91,7 @@ public class SDSDatabaseStorage: SDSTransactable { // completion is performed on the main queue. @objc public func runGrdbSchemaMigrations(completion: @escaping () -> Void) { - guard storageCoordinatorState == .GRDB, - canReadFromGrdb else { + guard storageCoordinatorState == .GRDB else { owsFailDebug("Not GRDB.") return } @@ -197,30 +157,6 @@ public class SDSDatabaseStorage: SDSTransactable { } func createGrdbStorage() -> GRDBDatabaseStorageAdapter { - if !canLoadGrdb { - Logger.error("storageMode: \(FeatureFlags.storageModeDescription).") - Logger.error( - "StorageCoordinatorState: \(storageCoordinatorStateDescription).") - Logger.error( - "dataStoreForUI: \(NSStringForDataStore(StorageCoordinator.dataStoreForUI)).") - - switch FeatureFlags.storageModeStrictness { - case .fail: - owsFail("Unexpected GRDB load.") - case .failDebug: - owsFailDebug("Unexpected GRDB load.") - case .log: - Logger.error("Unexpected GRDB load.") - } - } - - if FeatureFlags.storageMode == .ydbForAll { - owsFailDebug("Unexpected storage mode: \(FeatureFlags.storageModeDescription)") - } - if StorageCoordinator.dataStoreForUI == .ydb && !CurrentAppContext().isRunningTests { - owsFailDebug("Unexpected data store.") - } - return Bench(title: "Creating GRDB storage") { return GRDBDatabaseStorageAdapter(baseDir: type(of: self).baseDir()) } @@ -233,34 +169,10 @@ public class SDSDatabaseStorage: SDSTransactable { @objc public func resetAllStorage() { - OWSStorage.resetAllStorage() + YDBStorage.deleteYDBStorage() GRDBDatabaseStorageAdapter.resetAllStorage(baseDir: type(of: self).baseDir()) } - func createYapStorage() -> YAPDBStorageAdapter { - if !canLoadYdb { - Logger.error("storageMode: \(FeatureFlags.storageModeDescription).") - Logger.error( - "StorageCoordinatorState: \(storageCoordinatorStateDescription).") - Logger.error( - "dataStoreForUI: \(NSStringForDataStore(StorageCoordinator.dataStoreForUI)).") - - switch FeatureFlags.storageModeStrictness { - case .fail: - owsFail("Unexpected YDB load.") - case .failDebug: - owsFailDebug("Unexpected YDB load.") - case .log: - Logger.error("Unexpected YDB load.") - } - } - - return Bench(title: "Creating YDB storage") { - let yapPrimaryStorage = OWSPrimaryStorage() - return YAPDBStorageAdapter(storage: yapPrimaryStorage) - } - } - // MARK: - Observation @objc @@ -304,10 +216,6 @@ public class SDSDatabaseStorage: SDSTransactable { @objc public func updateIdMapping(thread: TSThread, transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite: - if !CurrentAppContext().isRunningTests { - owsFailDebug("Unexpected transaction.") - } case .grdbWrite(let grdb): UIDatabaseObserver.serializedSync { if let uiDatabaseObserver = grdbStorage.uiDatabaseObserver { @@ -322,10 +230,6 @@ public class SDSDatabaseStorage: SDSTransactable { @objc public func updateIdMapping(interaction: TSInteraction, transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite: - if !CurrentAppContext().isRunningTests { - owsFailDebug("Unexpected transaction.") - } case .grdbWrite(let grdb): UIDatabaseObserver.serializedSync { if let uiDatabaseObserver = grdbStorage.uiDatabaseObserver { @@ -340,10 +244,6 @@ public class SDSDatabaseStorage: SDSTransactable { @objc public func updateIdMapping(attachment: TSAttachment, transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite: - if !CurrentAppContext().isRunningTests { - owsFailDebug("Unexpected transaction.") - } case .grdbWrite(let grdb): UIDatabaseObserver.serializedSync { if let uiDatabaseObserver = grdbStorage.uiDatabaseObserver { @@ -360,9 +260,6 @@ public class SDSDatabaseStorage: SDSTransactable { @objc(touchInteraction:shouldReindex:transaction:) public func touch(interaction: TSInteraction, shouldReindex: Bool, transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let yap): - let uniqueId = interaction.uniqueId - yap.touchObject(forKey: uniqueId, inCollection: TSInteraction.collection()) case .grdbWrite(let grdb): UIDatabaseObserver.serializedSync { guard !UIDatabaseObserver.skipTouchObservations else { @@ -384,8 +281,6 @@ public class SDSDatabaseStorage: SDSTransactable { @objc(touchThread:shouldReindex:transaction:) public func touch(thread: TSThread, shouldReindex: Bool, transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let yap): - yap.touchObject(forKey: thread.uniqueId, inCollection: TSThread.collection()) case .grdbWrite(let grdb): UIDatabaseObserver.serializedSync { guard !UIDatabaseObserver.skipTouchObservations else { @@ -459,39 +354,23 @@ public class SDSDatabaseStorage: SDSTransactable { @objc public func uiRead(block: (SDSAnyReadTransaction) -> Void) { - switch dataStoreForReads { - case .grdb: - do { - try grdbStorage.uiRead { transaction in - block(transaction.asAnyRead) - } - } catch { - owsFail("error: \(error.grdbErrorForLogging)") - } - case .ydb: - owsFailDebug("YDB UI read.") - // We no longer use a UI connection with YDB. - yapStorage.read { transaction in + do { + try grdbStorage.uiRead { transaction in block(transaction.asAnyRead) } + } catch { + owsFail("error: \(error.grdbErrorForLogging)") } } @objc public override func read(block: (SDSAnyReadTransaction) -> Void) { - switch dataStoreForReads { - case .grdb: - do { - try grdbStorage.read { transaction in - block(transaction.asAnyRead) - } - } catch { - owsFail("error: \(error.grdbErrorForLogging)") - } - case .ydb: - yapStorage.read { transaction in + do { + try grdbStorage.read { transaction in block(transaction.asAnyRead) } + } catch { + owsFail("error: \(error.grdbErrorForLogging)") } } @@ -508,39 +387,21 @@ public class SDSDatabaseStorage: SDSTransactable { #endif let benchTitle = "Slow Write Transaction \(Self.owsFormatLogMessage(file: file, function: function, line: line))" - switch dataStoreForWrites { - case .grdb: - do { - try grdbStorage.write { transaction in - Bench(title: benchTitle, logIfLongerThan: 0.1, logInProduction: DebugFlags.internalLogging) { - block(transaction.asAnyWrite) - } - } - } catch { - owsFail("error: \(error.grdbErrorForLogging)") - } - case .ydb: - yapStorage.write { transaction in - Bench(title: benchTitle, logIfLongerThan: 0.1) { + do { + try grdbStorage.write { transaction in + Bench(title: benchTitle, logIfLongerThan: 0.1, logInProduction: DebugFlags.internalLogging) { block(transaction.asAnyWrite) } } + } catch { + owsFail("error: \(error.grdbErrorForLogging)") } crossProcess.notifyChangedAsync() } public func uiReadThrows(block: (SDSAnyReadTransaction) throws -> Void) throws { - switch dataStoreForReads { - case .grdb: - try grdbStorage.uiReadThrows { transaction in - try autoreleasepool { - try block(transaction.asAnyRead) - } - } - case .ydb: - owsFailDebug("YDB UI read.") - // We no longer use a UI connection with YDB. - try yapStorage.readThrows { transaction in + try grdbStorage.uiReadThrows { transaction in + try autoreleasepool { try block(transaction.asAnyRead) } } @@ -576,117 +437,7 @@ extension SDSDatabaseStorage { } private var storageCoordinatorStateDescription: String { - return NSStringFromStorageCoordinatorState(storageCoordinatorState) - } - - @objc - var dataStoreForReads: DataStore { - // Before the migration starts and during the migration, read from YDB. - switch storageCoordinatorState { - case .YDB, .beforeYDBToGRDBMigration, .duringYDBToGRDBMigration: - return .ydb - case .GRDB: - return .grdb - case .ydbTests: - return .ydb - case .grdbTests: - return .grdb - } - } - - @objc - var dataStoreForWrites: DataStore { - // Before the migration starts (but NOT during the migration), write to YDB. - switch storageCoordinatorState { - case .YDB, .beforeYDBToGRDBMigration: - return .ydb - case .duringYDBToGRDBMigration, .GRDB: - return .grdb - case .ydbTests: - return .ydb - case .grdbTests: - return .grdb - } - } - - private var dataStoreForReporting: DataStore { - return StorageCoordinator.dataStoreForUI - } - - @objc - var canLoadYdb: Bool { - switch storageCoordinatorState { - case .YDB, .beforeYDBToGRDBMigration, .duringYDBToGRDBMigration: - return true - case .GRDB: - return false - case .ydbTests, .grdbTests: - return true - } - } - - @objc - var canReadFromYdb: Bool { - // We can read from YDB before and during the YDB-to-GRDB migration. - switch storageCoordinatorState { - case .YDB, .beforeYDBToGRDBMigration, .duringYDBToGRDBMigration: - return true - case .GRDB: - return false - case .ydbTests, .grdbTests: - return true - } - } - - @objc - var canWriteToYdb: Bool { - // We can write to YDB before but not during the YDB-to-GRDB migration. - switch storageCoordinatorState { - case .YDB, .beforeYDBToGRDBMigration: - return true - case .duringYDBToGRDBMigration, .GRDB: - return false - case .ydbTests, .grdbTests: - return true - } - } - - @objc - var canLoadGrdb: Bool { - switch storageCoordinatorState { - case .YDB: - return false - case .beforeYDBToGRDBMigration, .duringYDBToGRDBMigration, .GRDB: - return true - case .ydbTests, .grdbTests: - return true - } - } - - @objc - var canReadFromGrdb: Bool { - // We can read from GRDB during but not before the YDB-to-GRDB migration. - switch storageCoordinatorState { - case .YDB, .beforeYDBToGRDBMigration: - return false - case .duringYDBToGRDBMigration, .GRDB: - return true - case .ydbTests, .grdbTests: - return true - } - } - - @objc - var canWriteToGrdb: Bool { - // We can write to GRDB during but not before the YDB-to-GRDB migration. - switch storageCoordinatorState { - case .YDB, .beforeYDBToGRDBMigration: - return false - case .duringYDBToGRDBMigration, .GRDB: - return true - case .ydbTests, .grdbTests: - return true - } + NSStringFromStorageCoordinatorState(storageCoordinatorState) } } @@ -736,42 +487,20 @@ public extension SDSDatabaseStorage { } func logAllFileSizes() { - if canLoadYdb { - Logger.info("YDB Database : \(yapStorage.databaseFileSize)") - Logger.info("\t YDB WAL file size: \(yapStorage.databaseWALFileSize)") - Logger.info("\t YDB SHM file size: \(yapStorage.databaseSHMFileSize)") - } - if canLoadGrdb { - Logger.info("GDRB Database : \(grdbStorage.databaseFileSize)") - Logger.info("\t GDRB WAL file size: \(grdbStorage.databaseWALFileSize)") - Logger.info("\t GDRB SHM file size: \(grdbStorage.databaseSHMFileSize)") - } + Logger.info("GDRB Database : \(grdbStorage.databaseFileSize)") + Logger.info("\t GDRB WAL file size: \(grdbStorage.databaseWALFileSize)") + Logger.info("\t GDRB SHM file size: \(grdbStorage.databaseSHMFileSize)") } var databaseFileSize: UInt64 { - switch dataStoreForReporting { - case .grdb: - return grdbStorage.databaseFileSize - case .ydb: - return yapStorage.databaseFileSize - } + grdbStorage.databaseFileSize } var databaseWALFileSize: UInt64 { - switch dataStoreForReporting { - case .grdb: - return grdbStorage.databaseWALFileSize - case .ydb: - return yapStorage.databaseWALFileSize - } + grdbStorage.databaseWALFileSize } var databaseSHMFileSize: UInt64 { - switch dataStoreForReporting { - case .grdb: - return grdbStorage.databaseSHMFileSize - case .ydb: - return yapStorage.databaseSHMFileSize - } + grdbStorage.databaseSHMFileSize } } diff --git a/SignalServiceKit/src/Storage/Database/SDSKeyValueStore.swift b/SignalServiceKit/src/Storage/Database/SDSKeyValueStore.swift index 4dfbc890dc..7f01c7d147 100644 --- a/SignalServiceKit/src/Storage/Database/SDSKeyValueStore.swift +++ b/SignalServiceKit/src/Storage/Database/SDSKeyValueStore.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // import Foundation @@ -16,7 +16,6 @@ public class SDSKeyValueStore: NSObject { // Key-value stores use "collections" to group related keys. // - // * In YDB, we store each model type and k-v store in a separate YDB collection. // * In GRDB, we store each model in a separate table but // all k-v stores are in a single table. // GRDB maintains a mapping between tables and collections. @@ -74,8 +73,6 @@ public class SDSKeyValueStore: NSObject { @objc public func hasValue(forKey key: String, transaction: SDSAnyReadTransaction) -> Bool { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: key, inCollection: collection) case .grdbRead(let grdbTransaction): do { let count = try UInt.fetchOne(grdbTransaction.database, @@ -321,8 +318,6 @@ public class SDSKeyValueStore: NSObject { @objc public func removeAll(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let yapWrite): - yapWrite.removeAllObjects(inCollection: collection) case .grdbWrite(let grdbWrite): let sql = """ DELETE @@ -336,10 +331,6 @@ public class SDSKeyValueStore: NSObject { @objc public func enumerateKeysAndObjects(transaction: SDSAnyReadTransaction, block: @escaping (String, Any, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeysAndObjects(inCollection: collection) { (key: String, value: Any, stopPtr: UnsafeMutablePointer) in - block(key, value, stopPtr) - } case .grdbRead(let grdbRead): var stop: ObjCBool = false // PERF - we could enumerate with a single query rather than @@ -361,10 +352,6 @@ public class SDSKeyValueStore: NSObject { @objc public func enumerateKeys(transaction: SDSAnyReadTransaction, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: collection) { (key: String, stopPtr: UnsafeMutablePointer) in - block(key, stopPtr) - } case .grdbRead(let grdbRead): var stop: ObjCBool = false for key in allKeys(grdbTransaction: grdbRead) { @@ -398,8 +385,6 @@ public class SDSKeyValueStore: NSObject { private func allPairs(transaction: SDSAnyReadTransaction) -> [PairRecord] { switch transaction.readTransaction { - case .yapRead: - owsFail("Invalid transaction") case .grdbRead(let grdbTransaction): let sql = """ @@ -464,8 +449,6 @@ public class SDSKeyValueStore: NSObject { @objc public func allKeys(transaction: SDSAnyReadTransaction) -> [String] { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.allKeys(inCollection: collection) case .grdbRead(let grdbRead): return allKeys(grdbTransaction: grdbRead) } @@ -474,8 +457,6 @@ public class SDSKeyValueStore: NSObject { @objc public func numberOfKeys(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: collection) case .grdbRead(let grdbRead): let sql = """ SELECT COUNT(*) @@ -547,11 +528,8 @@ public class SDSKeyValueStore: NSObject { } private func readRawObject(_ key: String, transaction: SDSAnyReadTransaction) -> Any? { - // YDB values are serialized by YDB. // GRDB values are serialized to data by this class. switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.object(forKey: key, inCollection: collection) case .grdbRead: guard let encoded = readData(key, transaction: transaction) else { return nil @@ -588,11 +566,6 @@ public class SDSKeyValueStore: NSObject { let collection = self.collection switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - guard let rawObject = ydbTransaction.object(forKey: key, inCollection: collection) else { - return nil - } - return parseValueAs(key: key, rawObject: rawObject) case .grdbRead(let grdbTransaction): return SDSKeyValueStore.readData(transaction: grdbTransaction, key: key, collection: collection) } @@ -611,15 +584,8 @@ public class SDSKeyValueStore: NSObject { // TODO: Codable? NSCoding? Other serialization? private func write(_ value: NSCoding?, forKey key: String, transaction: SDSAnyWriteTransaction) { - // YDB values are serialized by YDB. // GRDB values are serialized to data by this class. switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - if let value = value { - ydbTransaction.setObject(value, forKey: key, inCollection: collection) - } else { - ydbTransaction.removeObject(forKey: key, inCollection: collection) - } case .grdbWrite: if let value = value { let encoded = NSKeyedArchiver.archivedData(withRootObject: value) @@ -635,12 +601,6 @@ public class SDSKeyValueStore: NSObject { let collection = self.collection switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - if let data = data { - ydbTransaction.setObject(data, forKey: key, inCollection: collection) - } else { - ydbTransaction.removeObject(forKey: key, inCollection: collection) - } case .grdbWrite(let grdbTransaction): do { try SDSKeyValueStore.write(transaction: grdbTransaction, key: key, collection: collection, encoded: data) diff --git a/SignalServiceKit/src/Storage/Database/SDSModel.swift b/SignalServiceKit/src/Storage/Database/SDSModel.swift index cec8636536..dcb0413000 100644 --- a/SignalServiceKit/src/Storage/Database/SDSModel.swift +++ b/SignalServiceKit/src/Storage/Database/SDSModel.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // import Foundation @@ -36,8 +36,6 @@ public extension SDSModel { } switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydb_save(with: ydbTransaction) case .grdbWrite(let grdbTransaction): do { let record = try asRecord() @@ -72,8 +70,6 @@ public extension SDSModel { anyWillRemove(with: transaction) switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydb_remove(with: ydbTransaction) case .grdbWrite(let grdbTransaction): // Don't use a record to delete the record; // asRecord() is expensive. diff --git a/SignalServiceKit/src/Storage/Database/SDSTransaction.swift b/SignalServiceKit/src/Storage/Database/SDSTransaction.swift index cf52b70c4f..a78c731eaf 100644 --- a/SignalServiceKit/src/Storage/Database/SDSTransaction.swift +++ b/SignalServiceKit/src/Storage/Database/SDSTransaction.swift @@ -138,24 +138,15 @@ public class GRDBWriteTransaction: GRDBReadTransaction { // MARK: - -// Type erased transactions are generated at the top level (by DatabaseStorage) and can then be -// passed through an adapter which will be backed by either YapDB or GRDB -// -// To faciliate a gradual migration to GRDB features without breaking existing Yap functionality -// there are backdoors like `transitional_yapReadTransaction` which will unwrap -// the underlying YapDatabaseRead/WriteTransaction. @objc public class SDSAnyReadTransaction: NSObject { public enum ReadTransactionType { - case yapRead(_ transaction: YapDatabaseReadTransaction) case grdbRead(_ transaction: GRDBReadTransaction) } public let readTransaction: ReadTransactionType public var startDate: Date { switch readTransaction { - case .yapRead: - owsFail("Invalid transaction.") case .grdbRead(let grdbRead): return grdbRead.startDate } @@ -165,31 +156,8 @@ public class SDSAnyReadTransaction: NSObject { self.readTransaction = readTransaction } - // MARK: Transitional Methods - - // Useful to delineate where we're using SDSAnyReadTransaction if a specific - // feature hasn't been migrated and still requires a YapDatabaseReadTransaction - - @objc - public init(transitional_yapReadTransaction: YapDatabaseReadTransaction) { - self.readTransaction = .yapRead(transitional_yapReadTransaction) - } - - @objc - public var transitional_yapReadTransaction: YapDatabaseReadTransaction? { - switch readTransaction { - case .yapRead(let yapRead): - return yapRead - case .grdbRead: - return nil - } - } - - @objc public var isUIRead: Bool { switch readTransaction { - case .yapRead: - return false case .grdbRead(let grdbRead): return grdbRead.isUIRead } @@ -199,7 +167,6 @@ public class SDSAnyReadTransaction: NSObject { @objc public class SDSAnyWriteTransaction: SDSAnyReadTransaction, StoreContext { public enum WriteTransactionType { - case yapWrite(_ transaction: YapDatabaseReadWriteTransaction) case grdbWrite(_ transaction: GRDBWriteTransaction) } @@ -210,8 +177,6 @@ public class SDSAnyWriteTransaction: SDSAnyReadTransaction, StoreContext { let readTransaction: ReadTransactionType switch writeTransaction { - case .yapWrite(let yapWrite): - readTransaction = ReadTransactionType.yapRead(yapWrite) case .grdbWrite(let grdbWrite): readTransaction = ReadTransactionType.grdbRead(grdbWrite) } @@ -219,36 +184,11 @@ public class SDSAnyWriteTransaction: SDSAnyReadTransaction, StoreContext { super.init(readTransaction) } - // MARK: Transitional Methods - - // Useful to delineate where we're using SDSAnyReadTransaction if a specific - // feature hasn't been migrated and still requires a YapDatabaseReadTransaction - - @objc - public init(transitional_yapWriteTransaction: YapDatabaseReadWriteTransaction) { - self.writeTransaction = .yapWrite(transitional_yapWriteTransaction) - - super.init(transitional_yapReadTransaction: transitional_yapWriteTransaction) - } - - // GRDB TODO: Remove this method. - @objc - public var transitional_yapWriteTransaction: YapDatabaseReadWriteTransaction? { - switch writeTransaction { - case .yapWrite(let yapWrite): - return yapWrite - case .grdbWrite: - return nil - } - } - // NOTE: These completions are performed _after_ the write // transaction has completed. @objc public func addSyncCompletion(_ block: @escaping () -> Void) { switch writeTransaction { - case .yapWrite: - owsFailDebug("YDB transactions don't support sync completions.") case .grdbWrite(let grdbWrite): grdbWrite.addSyncCompletion(block: block) } @@ -269,8 +209,6 @@ public class SDSAnyWriteTransaction: SDSAnyReadTransaction, StoreContext { @objc public func addAsyncCompletion(queue: DispatchQueue = DispatchQueue.main, block: @escaping () -> Void) { switch writeTransaction { - case .yapWrite(let yapWrite): - yapWrite.addCompletionQueue(queue, completionBlock: block) case .grdbWrite(let grdbWrite): grdbWrite.addAsyncCompletion(queue: queue, block: block) } @@ -294,9 +232,6 @@ public class SDSAnyWriteTransaction: SDSAnyReadTransaction, StoreContext { public func addTransactionFinalizationBlock(forKey key: String, block: @escaping TransactionFinalizationBlock) { switch writeTransaction { - case .yapWrite: - // YDB transactions don't support deferred transaction finalizations. - block(self) case .grdbWrite(let grdbWrite): grdbWrite.addTransactionFinalizationBlock(forKey: key) { (transaction: GRDBWriteTransaction) in block(SDSAnyWriteTransaction(.grdbWrite(transaction))) @@ -307,39 +242,20 @@ public class SDSAnyWriteTransaction: SDSAnyReadTransaction, StoreContext { @objc public func addRemovedFinalizationKey(_ key: String) { switch writeTransaction { - case .yapWrite: - // YDB transactions don't support deferred transaction finalizations. - break case .grdbWrite(let grdbWrite): grdbWrite.addRemovedFinalizationKey(key) } } } +// MARK: - + public extension StoreContext { var asTransaction: SDSAnyWriteTransaction { return self as! SDSAnyWriteTransaction } } -// MARK: - - -@objc -public extension YapDatabaseReadTransaction { - var asAnyRead: SDSAnyReadTransaction { - return SDSAnyReadTransaction(transitional_yapReadTransaction: self) - } -} - -// MARK: - - -@objc -public extension YapDatabaseReadWriteTransaction { - var asAnyWrite: SDSAnyWriteTransaction { - return SDSAnyWriteTransaction(transitional_yapWriteTransaction: self) - } -} - // MARK: - Convenience Methods public extension GRDBWriteTransaction { @@ -375,8 +291,6 @@ public extension GRDBWriteTransaction { public extension SDSAnyReadTransaction { var unwrapGrdbRead: GRDBReadTransaction { switch readTransaction { - case .yapRead: - owsFail("Invalid transaction type.") case .grdbRead(let grdbRead): return grdbRead } @@ -389,38 +303,8 @@ public extension SDSAnyReadTransaction { public extension SDSAnyWriteTransaction { var unwrapGrdbWrite: GRDBWriteTransaction { switch writeTransaction { - case .yapWrite: - owsFail("Invalid transaction type.") case .grdbWrite(let grdbWrite): return grdbWrite } } } - -// MARK: - - -@objc -public extension SDSAnyReadTransaction { - var isYapRead: Bool { - switch readTransaction { - case .yapRead: - return true - case .grdbRead: - return false - } - } -} - -// MARK: - - -@objc -public extension SDSAnyWriteTransaction { - var isYapWrite: Bool { - switch writeTransaction { - case .yapWrite: - return true - case .grdbWrite: - return false - } - } -} diff --git a/SignalServiceKit/src/Storage/Database/Snapshots/ObservedDatabaseChanges.swift b/SignalServiceKit/src/Storage/Database/Snapshots/ObservedDatabaseChanges.swift index 391059ec65..a672579972 100644 --- a/SignalServiceKit/src/Storage/Database/Snapshots/ObservedDatabaseChanges.swift +++ b/SignalServiceKit/src/Storage/Database/Snapshots/ObservedDatabaseChanges.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // import Foundation @@ -495,7 +495,6 @@ extension ObservedDatabaseChanges: UIDatabaseChanges { @objc(didUpdateKeyValueStore:) func didUpdate(keyValueStore: SDSKeyValueStore) -> Bool { - // YDB: keyValueStore.collection // GRDB: SDSKeyValueStore.dataStoreCollection return (didUpdate(collection: keyValueStore.collection) || didUpdate(collection: SDSKeyValueStore.dataStoreCollection)) diff --git a/SignalServiceKit/src/Storage/Database/YAPDBStorageAdapter.swift b/SignalServiceKit/src/Storage/Database/YAPDBStorageAdapter.swift deleted file mode 100644 index 39d89286d8..0000000000 --- a/SignalServiceKit/src/Storage/Database/YAPDBStorageAdapter.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -import Foundation - -struct YAPDBStorageAdapter { - let storage: OWSPrimaryStorage -} - -// MARK: - - -extension YAPDBStorageAdapter: SDSDatabaseStorageAdapter { - func readThrows(block: (YapDatabaseReadTransaction) throws -> Void) throws { - try withoutActuallyEscaping(block) { block in - var errorToRaise: Error? - storage.dbReadConnection.read { yapTransaction in - do { - try block(yapTransaction) - } catch { - errorToRaise = error - } - } - if let error = errorToRaise { - throw error - } - } - } - - func uiRead(block: (YapDatabaseReadTransaction) -> Void) { - withoutActuallyEscaping(block) { block in - owsFailDebug("YDB UI read.") - storage.dbReadConnection.read { yapTransaction in - block(yapTransaction) - } - } - } - - func read(block: (YapDatabaseReadTransaction) -> Void) { - withoutActuallyEscaping(block) { block in - storage.dbReadConnection.read { yapTransaction in - block(yapTransaction) - } - } - } - - func write(block: (YapDatabaseReadWriteTransaction) -> Void) { - withoutActuallyEscaping(block) { block in - storage.dbReadWriteConnection.readWrite { yapTransaction in - block(yapTransaction) - } - } - } -} - -// MARK: - Reporting - -extension YAPDBStorageAdapter { - var databaseFileSize: UInt64 { - return OWSPrimaryStorage.shared?.databaseFileSize() ?? 0 - } - - var databaseWALFileSize: UInt64 { - return OWSPrimaryStorage.shared?.databaseWALFileSize() ?? 0 - } - - var databaseSHMFileSize: UInt64 { - return OWSPrimaryStorage.shared?.databaseSHMFileSize() ?? 0 - } -} diff --git a/SignalServiceKit/src/Storage/FullTextSearchFinder.swift b/SignalServiceKit/src/Storage/FullTextSearchFinder.swift index e68dcd0f4f..6d9230f2d5 100644 --- a/SignalServiceKit/src/Storage/FullTextSearchFinder.swift +++ b/SignalServiceKit/src/Storage/FullTextSearchFinder.swift @@ -9,8 +9,6 @@ import GRDB public class FullTextSearchFinder: NSObject { public func enumerateObjects(searchText: String, transaction: SDSAnyReadTransaction, block: @escaping (Any, String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead: - owsFailDebug("YDB FTS no longer supported.") case .grdbRead(let grdbRead): GRDBFullTextSearchFinder.enumerateObjects(searchText: searchText, transaction: grdbRead, block: block) } @@ -20,9 +18,6 @@ public class FullTextSearchFinder: NSObject { assert(type(of: model).shouldBeIndexedForFTS) switch transaction.writeTransaction { - case .yapWrite: - // Do nothing. - break case .grdbWrite(let grdbWrite): GRDBFullTextSearchFinder.modelWasInserted(model: model, transaction: grdbWrite) } @@ -41,9 +36,6 @@ public class FullTextSearchFinder: NSObject { assert(type(of: model).shouldBeIndexedForFTS) switch transaction.writeTransaction { - case .yapWrite: - // Do nothing. - break case .grdbWrite(let grdbWrite): GRDBFullTextSearchFinder.modelWasUpdated(model: model, transaction: grdbWrite) } @@ -53,9 +45,6 @@ public class FullTextSearchFinder: NSObject { assert(type(of: model).shouldBeIndexedForFTS) switch transaction.writeTransaction { - case .yapWrite: - // Do nothing. - break case .grdbWrite(let grdbWrite): GRDBFullTextSearchFinder.modelWasRemoved(model: model, transaction: grdbWrite) } @@ -63,9 +52,6 @@ public class FullTextSearchFinder: NSObject { public class func allModelsWereRemoved(collection: String, transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite: - // Do nothing. - break case .grdbWrite(let grdbWrite): GRDBFullTextSearchFinder.allModelsWereRemoved(collection: collection, transaction: grdbWrite) } @@ -140,8 +126,7 @@ extension FullTextSearchFinder { // MARK: - Querying -// We use SQLite's FTS5 for both YDB and GRDB, we can use the -// same query for both cases. +// We use SQLite's FTS5 for GRDB. extension FullTextSearchFinder { // We want to match by prefix for "search as you type" functionality. diff --git a/SignalServiceKit/src/Storage/Jobs/SSKJobRecord+SDS.swift b/SignalServiceKit/src/Storage/Jobs/SSKJobRecord+SDS.swift index 2a27d96396..1fbb2c750c 100644 --- a/SignalServiceKit/src/Storage/Jobs/SSKJobRecord+SDS.swift +++ b/SignalServiceKit/src/Storage/Jobs/SSKJobRecord+SDS.swift @@ -683,8 +683,6 @@ public extension SSKJobRecord { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return SSKJobRecord.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(JobRecordRecord.databaseTableName) WHERE \(jobRecordColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -715,14 +713,6 @@ public extension SSKJobRecord { batchSize: UInt, block: @escaping (SSKJobRecord, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - SSKJobRecord.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? SSKJobRecord else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = SSKJobRecord.grdbFetchCursor(transaction: grdbTransaction) @@ -764,10 +754,6 @@ public extension SSKJobRecord { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: SSKJobRecord.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -799,8 +785,6 @@ public extension SSKJobRecord { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: SSKJobRecord.collection()) case .grdbRead(let grdbTransaction): return JobRecordRecord.ows_fetchCount(grdbTransaction.database) } @@ -810,8 +794,6 @@ public extension SSKJobRecord { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: SSKJobRecord.collection()) case .grdbWrite(let grdbTransaction): do { try JobRecordRecord.deleteAll(grdbTransaction.database) @@ -860,8 +842,6 @@ public extension SSKJobRecord { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: SSKJobRecord.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(JobRecordRecord.databaseTableName) WHERE \(jobRecordColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Storage/Jobs/SSKJobRecord.m b/SignalServiceKit/src/Storage/Jobs/SSKJobRecord.m index 453da586ff..3a4baa24e3 100644 --- a/SignalServiceKit/src/Storage/Jobs/SSKJobRecord.m +++ b/SignalServiceKit/src/Storage/Jobs/SSKJobRecord.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // #import "SSKJobRecord.h" @@ -82,18 +82,6 @@ NSErrorDomain const SSKJobRecordErrorDomain = @"SignalServiceKit.JobRecord"; return @"JobRecord"; } -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-implementations" -- (void)ydb_saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - // This is *only* for Yap. For GRDB we get the sortId from the DB autoincrement column - if (self.sortId == 0) { - self.sortId = [SSKIncrementingIdFinder nextIdWithKey:self.class.collection transaction:transaction]; - } - [super ydb_saveWithTransaction:transaction]; -} -#pragma clang diagnostic pop - #pragma mark - - (void)updateStatus:(SSKJobRecordStatus)status transaction:(SDSAnyWriteTransaction *)transaction diff --git a/SignalServiceKit/src/Storage/MediaGalleryFinder.swift b/SignalServiceKit/src/Storage/MediaGalleryFinder.swift index a21b6967a8..f928daf34d 100644 --- a/SignalServiceKit/src/Storage/MediaGalleryFinder.swift +++ b/SignalServiceKit/src/Storage/MediaGalleryFinder.swift @@ -85,8 +85,6 @@ public final class MediaGalleryManager: NSObject { @objc(didInsertAttachmentStream:transaction:) public class func didInsert(attachmentStream: TSAttachmentStream, transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite: - break case .grdbWrite(let grdbWrite): do { try insertGalleryRecord(attachmentStream: attachmentStream, transaction: grdbWrite) @@ -99,8 +97,6 @@ public final class MediaGalleryManager: NSObject { @objc(didRemoveAttachmentStream:transaction:) public class func didRemove(attachmentStream: TSAttachmentStream, transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite: - break case .grdbWrite(let grdbWrite): do { try removeAnyGalleryRecord(attachmentStream: attachmentStream, transaction: grdbWrite) @@ -113,8 +109,6 @@ public final class MediaGalleryManager: NSObject { @objc public class func didRemoveAllContent(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite: - break case .grdbWrite(let grdbWrite): do { try removeAllGalleryRecords(transaction: grdbWrite) diff --git a/SignalServiceKit/src/Storage/OWSIncomingMessageFinder.h b/SignalServiceKit/src/Storage/OWSIncomingMessageFinder.h deleted file mode 100644 index 4382e59fdd..0000000000 --- a/SignalServiceKit/src/Storage/OWSIncomingMessageFinder.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -@class OWSStorage; -@class SignalServiceAddress; -@class YapDatabaseReadTransaction; - -@interface OWSIncomingMessageFinder : NSObject - -+ (void)asyncRegisterExtensionWithPrimaryStorage:(OWSStorage *)storage; - -/** - * Detects existance of a duplicate incoming message. - */ -- (BOOL)existsMessageWithTimestamp:(uint64_t)timestamp - address:(SignalServiceAddress *)address - sourceDeviceId:(uint32_t)sourceDeviceId - transaction:(YapDatabaseReadTransaction *)transaction; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/OWSIncomingMessageFinder.m b/SignalServiceKit/src/Storage/OWSIncomingMessageFinder.m deleted file mode 100644 index 37473e3245..0000000000 --- a/SignalServiceKit/src/Storage/OWSIncomingMessageFinder.m +++ /dev/null @@ -1,131 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSIncomingMessageFinder.h" -#import "OWSStorage.h" -#import "TSIncomingMessage.h" -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -NSString *const OWSIncomingMessageFinderExtensionName = @"OWSIncomingMessageFinderExtensionName"; - -NSString *const OWSIncomingMessageFinderColumnTimestamp = @"OWSIncomingMessageFinderColumnTimestamp"; -NSString *const OWSIncomingMessageFinderColumnPhoneNumber = @"OWSIncomingMessageFinderColumnPhoneNumber"; -NSString *const OWSIncomingMessageFinderColumnUUID = @"OWSIncomingMessageFinderColumnUUID"; -NSString *const OWSIncomingMessageFinderColumnSourceDeviceId = @"OWSIncomingMessageFinderColumnSourceDeviceId"; - -@implementation OWSIncomingMessageFinder - -#pragma mark - init - -- (instancetype)init -{ - self = [super init]; - if (!self) { - return self; - } - - return self; -} - -#pragma mark - YAP integration - -+ (YapDatabaseSecondaryIndex *)indexExtension -{ - YapDatabaseSecondaryIndexSetup *setup = [YapDatabaseSecondaryIndexSetup new]; - - [setup addColumn:OWSIncomingMessageFinderColumnTimestamp withType:YapDatabaseSecondaryIndexTypeInteger]; - [setup addColumn:OWSIncomingMessageFinderColumnPhoneNumber withType:YapDatabaseSecondaryIndexTypeText]; - [setup addColumn:OWSIncomingMessageFinderColumnUUID withType:YapDatabaseSecondaryIndexTypeText]; - [setup addColumn:OWSIncomingMessageFinderColumnSourceDeviceId withType:YapDatabaseSecondaryIndexTypeInteger]; - - YapDatabaseSecondaryIndexWithObjectBlock block = ^(YapDatabaseReadTransaction *transaction, - NSMutableDictionary *dict, - NSString *collection, - NSString *key, - id object) { - if ([object isKindOfClass:[TSIncomingMessage class]]) { - TSIncomingMessage *incomingMessage = (TSIncomingMessage *)object; - - // On new messages authorId should be set on all incoming messages, but there was a time when authorId was - // only set on incoming group messages. - NSObject *phoneNumberOrNull = incomingMessage.authorAddress.phoneNumber ?: [NSNull null]; - NSObject *uuidStringOrNull = incomingMessage.authorAddress.uuidString ?: [NSNull null]; - [dict setObject:@(incomingMessage.timestamp) forKey:OWSIncomingMessageFinderColumnTimestamp]; - [dict setObject:phoneNumberOrNull forKey:OWSIncomingMessageFinderColumnPhoneNumber]; - [dict setObject:uuidStringOrNull forKey:OWSIncomingMessageFinderColumnUUID]; - [dict setObject:@(incomingMessage.sourceDeviceId) forKey:OWSIncomingMessageFinderColumnSourceDeviceId]; - } - }; - - YapDatabaseSecondaryIndexHandler *handler = [YapDatabaseSecondaryIndexHandler withObjectBlock:block]; - - return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler versionTag:@"1"]; -} - -+ (NSString *)databaseExtensionName -{ - return OWSIncomingMessageFinderExtensionName; -} - -+ (void)asyncRegisterExtensionWithPrimaryStorage:(OWSStorage *)storage -{ - OWSLogInfo(@"registering async."); - [storage asyncRegisterExtension:self.indexExtension withName:OWSIncomingMessageFinderExtensionName]; -} - -#pragma mark - instance methods - -- (BOOL)existsMessageWithTimestamp:(uint64_t)timestamp - address:(SignalServiceAddress *)address - sourceDeviceId:(uint32_t)sourceDeviceId - transaction:(YapDatabaseReadTransaction *)transaction -{ - NSUInteger count = 0; - - if (address.uuidString) { - NSString *queryFormat = [NSString stringWithFormat:@"WHERE %@ = ? AND %@ = ? AND %@ = ?", - OWSIncomingMessageFinderColumnTimestamp, - OWSIncomingMessageFinderColumnSourceDeviceId, - OWSIncomingMessageFinderColumnUUID]; - - // YapDatabaseQuery params must be objects - YapDatabaseQuery *query = - [YapDatabaseQuery queryWithFormat:queryFormat, @(timestamp), @(sourceDeviceId), address.uuidString]; - - BOOL success = [[transaction ext:OWSIncomingMessageFinderExtensionName] getNumberOfRows:&count - matchingQuery:query]; - if (!success) { - OWSFailDebug(@"Could not execute query"); - return NO; - } - } - - if (count == 0 && address.phoneNumber) { - NSString *queryFormat = [NSString stringWithFormat:@"WHERE %@ = ? AND %@ = ? AND %@ = ?", - OWSIncomingMessageFinderColumnTimestamp, - OWSIncomingMessageFinderColumnSourceDeviceId, - OWSIncomingMessageFinderColumnPhoneNumber]; - - // YapDatabaseQuery params must be objects - YapDatabaseQuery *query = - [YapDatabaseQuery queryWithFormat:queryFormat, @(timestamp), @(sourceDeviceId), address.phoneNumber]; - - BOOL success = [[transaction ext:OWSIncomingMessageFinderExtensionName] getNumberOfRows:&count - matchingQuery:query]; - if (!success) { - OWSFailDebug(@"Could not execute query"); - return NO; - } - } - - return count > 0; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/OWSPrimaryStorage.h b/SignalServiceKit/src/Storage/OWSPrimaryStorage.h deleted file mode 100644 index b7d2fd169b..0000000000 --- a/SignalServiceKit/src/Storage/OWSPrimaryStorage.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import "OWSStorage.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSPrimaryStorage : OWSStorage - -- (instancetype)init NS_DESIGNATED_INITIALIZER; - -@property (nonatomic, readonly) YapDatabaseConnection *dbReadConnection; -@property (nonatomic, readonly) YapDatabaseConnection *dbReadWriteConnection; -@property (class, nonatomic, readonly) YapDatabaseConnection *dbReadConnection; -@property (class, nonatomic, readonly) YapDatabaseConnection *dbReadWriteConnection; - -+ (nullable NSError *)migrateToSharedData; - -+ (NSString *)databaseFilePath; - -+ (NSString *)legacyDatabaseFilePath; -+ (NSString *)legacyDatabaseFilePath_SHM; -+ (NSString *)legacyDatabaseFilePath_WAL; -+ (NSString *)sharedDataDatabaseFilePath; -+ (NSString *)sharedDataDatabaseFilePath_SHM; -+ (NSString *)sharedDataDatabaseFilePath_WAL; - -+ (NSString *)legacyDatabaseDirPath; -+ (NSString *)sharedDataDatabaseDirPath; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m deleted file mode 100644 index 0bb1579e24..0000000000 --- a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m +++ /dev/null @@ -1,393 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import "OWSPrimaryStorage.h" -#import "AppContext.h" -#import "OWSAnalytics.h" -#import "OWSDisappearingMessagesFinder.h" -#import "OWSFailedAttachmentDownloadsJob.h" -#import "OWSFailedMessagesJob.h" -#import "OWSFileSystem.h" -#import "OWSIncomingMessageFinder.h" -#import "OWSIncompleteCallsJob.h" -#import "OWSStorage+Subclass.h" -#import "SSKEnvironment.h" -#import "TSDatabaseSecondaryIndexes.h" -#import "TSDatabaseView.h" -#import "YAPDBMediaGalleryManager.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage, dispatch_block_t completion) -{ - OWSCAssertDebug(storage); - - [[storage newDatabaseConnection] asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) { - for (NSString *extensionName in storage.registeredExtensionNames) { - OWSLogVerbose(@"Verifying database extension: %@", extensionName); - YapDatabaseViewTransaction *_Nullable viewTransaction = [transaction ext:extensionName]; - if (!viewTransaction) { - OWSCFailDebug(@"VerifyRegistrationsForPrimaryStorage missing database extension: %@", extensionName); - - [OWSStorage incrementVersionOfDatabaseExtension:extensionName]; - } - } - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), completion); - }]; -} - -#pragma mark - - -@interface OWSPrimaryStorage () - -@property (atomic) BOOL areAsyncRegistrationsComplete; -@property (atomic) BOOL areSyncRegistrationsComplete; -@property (nonatomic, readonly) YapDatabaseConnectionPool *dbReadPool; - -@end - -#pragma mark - - -@implementation OWSPrimaryStorage - -- (instancetype)init -{ - self = [super init]; - - if (self) { - [self loadDatabase]; - - _dbReadPool = [[YapDatabaseConnectionPool alloc] initWithDatabase:self.database]; - self.dbReadPool.connectionLimit = 10; - - _dbReadWriteConnection = [self newDatabaseConnection]; - - [OWSPrimaryStorage protectFiles]; - - OWSSingletonAssert(); - } - - return self; -} - -- (void)dealloc -{ - // Surface memory leaks by logging the deallocation of this class. - OWSLogVerbose(@"Dealloc: %@", self.class); - - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (void)resetStorage -{ - _dbReadPool = nil; - _dbReadWriteConnection = nil; - - [super resetStorage]; -} - -- (void)runSyncRegistrations -{ - // Synchronously register extensions which are essential for views. - [TSDatabaseView registerCrossProcessNotifier:self]; - - // See comments on OWSDatabaseConnection. - // - // In the absence of finding documentation that can shed light on the issue we've been - // seeing, this issue only seems to affect sync and not async registrations. We've always - // been opening write transactions before the async registrations complete without negative - // consequences. - OWSAssertDebug(!self.areSyncRegistrationsComplete); - self.areSyncRegistrationsComplete = YES; -} - -- (void)runAsyncRegistrationsWithCompletion:(void (^_Nonnull)(void))completion -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(completion); - OWSAssertDebug(self.database); - - OWSLogVerbose(@"async registrations enqueuing."); - - // Asynchronously register other extensions. - // - // All sync registrations must be done before all async registrations, - // or the sync registrations will block on the async registrations. - [TSDatabaseView asyncRegisterLegacyThreadInteractionsDatabaseView:self]; - - [TSDatabaseView asyncRegisterThreadInteractionsDatabaseView:self]; - - [self.database - flushExtensionRequestsWithCompletionQueue:dispatch_get_main_queue() - completionBlock:^{ - OWSAssertIsOnMainThread(); - - // Building this view requires TSMessageDatabaseViewExtensionName which is - // registered above in asyncRegisterThreadInteractionsDatabaseView. - [TSDatabaseView asyncRegisterThreadDatabaseView:self]; - - [self asyncRegisterExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex] - withName:[TSDatabaseSecondaryIndexes - registerTimeStampIndexExtensionName]]; - - [YAPDBMessageContentJobFinder asyncRegisterDatabaseExtension:self]; - - [TSDatabaseView asyncRegisterThreadOutgoingMessagesDatabaseView:self]; - [TSDatabaseView asyncRegisterThreadSpecialMessagesDatabaseView:self]; - [TSDatabaseView asyncRegisterIncompleteViewOnceMessagesDatabaseView:self]; - [TSDatabaseView asyncRegisterInteractionsBySortIdDatabaseView:self]; - - [YAPDBSignalServiceAddressIndex asyncRegisterDatabaseExtensions:self]; - [OWSIncomingMessageFinder asyncRegisterExtensionWithPrimaryStorage:self]; - [OWSDisappearingMessagesFinder asyncRegisterDatabaseExtensions:self]; - [OWSFailedMessagesJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; - [OWSIncompleteCallsJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; - [OWSFailedAttachmentDownloadsJob - asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; - [YAPDBMediaGalleryManager asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; - [TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:self]; - [YAPDBJobRecordFinderSetup asyncRegisterDatabaseExtensionObjCWithStorage:self]; - [YAPDBUserProfileFinder asyncRegisterDatabaseExtensions:self]; - [OWSMessageDecryptJobFinder asyncRegisterDatabaseExtension:self]; - - [self.database - flushExtensionRequestsWithCompletionQueue:dispatch_get_global_queue( - DISPATCH_QUEUE_PRIORITY_DEFAULT, - 0) - completionBlock:^{ - OWSAssertDebug( - !self.areAsyncRegistrationsComplete); - OWSLogVerbose(@"async registrations complete."); - - // We verify that all database views registered - // successfully and are accessible on launch - // _before_ "database is ready". This ensures - // that if a view becomes corrupted it, we - // detect that now and increment the view - // version, so that it will be rebuilt on next - // launch. Otherwise, the app might crash later - // in a place that won't increment the view - // version. - VerifyRegistrationsForPrimaryStorage(self, ^{ - self.areAsyncRegistrationsComplete = YES; - - completion(); - }); - }]; - }]; -} - -+ (void)protectFiles -{ - OWSLogInfo(@"Database file size: %@", [OWSFileSystem fileSizeOfPath:self.sharedDataDatabaseFilePath]); - OWSLogInfo(@"\t SHM file size: %@", [OWSFileSystem fileSizeOfPath:self.sharedDataDatabaseFilePath_SHM]); - OWSLogInfo(@"\t WAL file size: %@", [OWSFileSystem fileSizeOfPath:self.sharedDataDatabaseFilePath_WAL]); - - // Protect the entire new database directory. - [OWSFileSystem protectFileOrFolderAtPath:self.ensureSharedDataDatabaseFilePath]; -} - -+ (NSString *)legacyDatabaseDirPath -{ - return [OWSFileSystem appDocumentDirectoryPath]; -} - -+ (NSString *)sharedDataDatabaseDirPath -{ - return [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"database"]; -} - -+ (NSString *)ensureSharedDataDatabaseFilePath -{ - NSString *databaseDirPath = self.sharedDataDatabaseDirPath; - if (![OWSFileSystem ensureDirectoryExists:databaseDirPath]) { - OWSFail(@"Could not create new database directory"); - } - return databaseDirPath; -} - -+ (NSString *)databaseFilename -{ - return @"Signal.sqlite"; -} - -+ (NSString *)databaseFilename_SHM -{ - return [self.databaseFilename stringByAppendingString:@"-shm"]; -} - -+ (NSString *)databaseFilename_WAL -{ - return [self.databaseFilename stringByAppendingString:@"-wal"]; -} - -+ (NSString *)legacyDatabaseFilePath -{ - return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename]; -} - -+ (NSString *)legacyDatabaseFilePath_SHM -{ - return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_SHM]; -} - -+ (NSString *)legacyDatabaseFilePath_WAL -{ - return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL]; -} - -+ (NSString *)sharedDataDatabaseFilePath -{ - return [self.ensureSharedDataDatabaseFilePath stringByAppendingPathComponent:self.databaseFilename]; -} - -+ (NSString *)sharedDataDatabaseFilePath_SHM -{ - return [self.ensureSharedDataDatabaseFilePath stringByAppendingPathComponent:self.databaseFilename_SHM]; -} - -+ (NSString *)sharedDataDatabaseFilePath_WAL -{ - return [self.ensureSharedDataDatabaseFilePath stringByAppendingPathComponent:self.databaseFilename_WAL]; -} - -+ (nullable NSError *)migrateToSharedData -{ - OWSLogInfo(@""); - - // Given how sensitive this migration is, we verbosely - // log the contents of all involved paths before and after. - NSArray *paths = @[ - self.legacyDatabaseFilePath, - self.legacyDatabaseFilePath_SHM, - self.legacyDatabaseFilePath_WAL, - self.sharedDataDatabaseFilePath, - self.sharedDataDatabaseFilePath_SHM, - self.sharedDataDatabaseFilePath_WAL, - ]; - NSFileManager *fileManager = [NSFileManager defaultManager]; - for (NSString *path in paths) { - if ([fileManager fileExistsAtPath:path]) { - OWSLogInfo(@"before migrateToSharedData: %@, %@", path, [OWSFileSystem fileSizeOfPath:path]); - } - } - - // We protect the db files here, which is somewhat redundant with what will happen in - // `moveAppFilePath:` which also ensures file protection. - // However that method dispatches async, since it can take a while with large attachment directories. - // - // Since we only have three files here it'll be quick to do it sync, and we want to make - // sure it happens as part of the migration. - // - // FileProtection attributes move with the file, so we do it on the legacy files before moving - // them. - [OWSFileSystem protectFileOrFolderAtPath:self.legacyDatabaseFilePath]; - [OWSFileSystem protectFileOrFolderAtPath:self.legacyDatabaseFilePath_SHM]; - [OWSFileSystem protectFileOrFolderAtPath:self.legacyDatabaseFilePath_WAL]; - - NSError *_Nullable error = nil; - if ([fileManager fileExistsAtPath:self.legacyDatabaseFilePath] && - [fileManager fileExistsAtPath:self.sharedDataDatabaseFilePath]) { - // In the case that we have a "database conflict" (i.e. database files - // in the src and dst locations), ensure database integrity by renaming - // all of the dst database files. - for (NSString *filePath in @[ - self.sharedDataDatabaseFilePath, - self.sharedDataDatabaseFilePath_SHM, - self.sharedDataDatabaseFilePath_WAL, - ]) { - error = [OWSFileSystem renameFilePathUsingRandomExtension:filePath]; - if (error) { - return error; - } - } - } - - error = - [OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath sharedDataFilePath:self.sharedDataDatabaseFilePath]; - if (error) { - return error; - } - error = [OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath_SHM - sharedDataFilePath:self.sharedDataDatabaseFilePath_SHM]; - if (error) { - return error; - } - error = [OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath_WAL - sharedDataFilePath:self.sharedDataDatabaseFilePath_WAL]; - if (error) { - return error; - } - - for (NSString *path in paths) { - if ([fileManager fileExistsAtPath:path]) { - OWSLogInfo(@"after migrateToSharedData: %@, %@", path, [OWSFileSystem fileSizeOfPath:path]); - } - } - - return nil; -} - -+ (NSString *)databaseFilePath -{ - OWSLogVerbose(@"databasePath: %@", OWSPrimaryStorage.sharedDataDatabaseFilePath); - - return self.sharedDataDatabaseFilePath; -} - -+ (NSString *)databaseFilePath_SHM -{ - return self.sharedDataDatabaseFilePath_SHM; -} - -+ (NSString *)databaseFilePath_WAL -{ - return self.sharedDataDatabaseFilePath_WAL; -} - -- (NSString *)databaseFilePath -{ - return OWSPrimaryStorage.databaseFilePath; -} - -- (NSString *)databaseFilePath_SHM -{ - return OWSPrimaryStorage.databaseFilePath_SHM; -} - -- (NSString *)databaseFilePath_WAL -{ - return OWSPrimaryStorage.databaseFilePath_WAL; -} - -- (NSString *)databaseFilename_SHM -{ - return OWSPrimaryStorage.databaseFilename_SHM; -} - -- (NSString *)databaseFilename_WAL -{ - return OWSPrimaryStorage.databaseFilename_WAL; -} - -+ (YapDatabaseConnection *)dbReadConnection -{ - return OWSPrimaryStorage.shared.dbReadConnection; -} - -- (YapDatabaseConnection *)dbReadConnection -{ - return self.dbReadPool.connection; -} - -+ (YapDatabaseConnection *)dbReadWriteConnection -{ - return OWSPrimaryStorage.shared.dbReadWriteConnection; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/OWSStorage+Subclass.h b/SignalServiceKit/src/Storage/OWSStorage+Subclass.h index 5808c2863f..552a8c8280 100644 --- a/SignalServiceKit/src/Storage/OWSStorage+Subclass.h +++ b/SignalServiceKit/src/Storage/OWSStorage+Subclass.h @@ -1,32 +1,5 @@ // -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // -#import "OWSStorage.h" -NS_ASSUME_NONNULL_BEGIN - -@class YapDatabase; - -@interface OWSStorage (Subclass) - -@property (atomic, nullable, readonly) YapDatabase *database; - -- (void)loadDatabase; - -- (void)runSyncRegistrations; -// completion will be invoked _off_ the main thread. -- (void)runAsyncRegistrationsWithCompletion:(void (^_Nonnull)(void))completion; - -- (BOOL)areAsyncRegistrationsComplete; -- (BOOL)areSyncRegistrationsComplete; - -- (NSString *)databaseFilePath; -- (NSString *)databaseFilePath_SHM; -- (NSString *)databaseFilePath_WAL; - -- (void)resetStorage; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/OWSStorage.h b/SignalServiceKit/src/Storage/OWSStorage.h deleted file mode 100644 index 6e6465c11e..0000000000 --- a/SignalServiceKit/src/Storage/OWSStorage.h +++ /dev/null @@ -1,119 +0,0 @@ -// -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class YapDatabaseExtension; - -@protocol OWSDatabaseConnectionDelegate - -- (BOOL)areAllRegistrationsComplete; - -@end - -#pragma mark - - -@interface OWSDatabaseConnection : YapDatabaseConnection - -@property (atomic, weak) id delegate; -@property (atomic) BOOL isCleanupConnection; - -+ (instancetype)new NS_UNAVAILABLE; -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithDatabase:(YapDatabase *)database - delegate:(id)delegate NS_DESIGNATED_INITIALIZER; - -@end - -#pragma mark - - -@interface OWSDatabase : YapDatabase - -+ (instancetype)new NS_UNAVAILABLE; -- (instancetype)init NS_UNAVAILABLE; - -- (id)initWithPath:(NSString *)inPath - serializer:(nullable YapDatabaseSerializer)inSerializer - deserializer:(YapDatabaseDeserializer)inDeserializer - options:(YapDatabaseOptions *)inOptions - delegate:(id)delegate NS_DESIGNATED_INITIALIZER; - -@end - -#pragma mark - - -typedef void (^OWSStorageCompletionBlock)(void); - -@interface OWSStorage : NSObject - -- (instancetype)init NS_DESIGNATED_INITIALIZER; - -// Returns YES if _ALL_ storage classes have completed both their -// sync _AND_ async view registrations. -+ (BOOL)isStorageReady; - -// This object can be used to filter database notifications. -@property (nonatomic, readonly, nullable) id dbNotificationObject; - -// completionBlock will be invoked _off_ the main thread. -+ (void)registerExtensionsWithCompletionBlock:(OWSStorageCompletionBlock)completionBlock; - -#ifdef DEBUG -- (void)closeStorageForTests; -#endif - -+ (void)resetAllStorage; - -- (YapDatabaseConnection *)newDatabaseConnection; - -+ (YapDatabaseOptions *)defaultDatabaseOptions; - -#pragma mark - Extension Registration - -+ (void)incrementVersionOfDatabaseExtension:(NSString *)extensionName; - -- (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName; - -- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName; -- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension - withName:(NSString *)extensionName - completion:(nullable dispatch_block_t)completion; - -- (nullable id)registeredExtension:(NSString *)extensionName; - -- (NSArray *)registeredExtensionNames; - -#pragma mark - - -- (unsigned long long)databaseFileSize; -- (unsigned long long)databaseWALFileSize; -- (unsigned long long)databaseSHMFileSize; - -- (YapDatabaseConnection *)registrationConnection; - -#pragma mark - Password - -/** - * Returns NO if: - * - * - Keychain is locked because device has just been restarted. - * - Password could not be retrieved because of a keychain error. - */ -+ (BOOL)isDatabasePasswordAccessible; - -+ (nullable NSData *)tryToLoadDatabaseLegacyPassphrase:(NSError **)errorHandle; -+ (void)removeLegacyPassphrase; - -+ (void)storeDatabaseCipherKeySpec:(NSData *)cipherKeySpecData; - -#pragma mark - Reset - -+ (void)deleteDatabaseFiles; -+ (void)deleteDBKeys; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/OWSStorage.m b/SignalServiceKit/src/Storage/OWSStorage.m deleted file mode 100644 index 5a28630236..0000000000 --- a/SignalServiceKit/src/Storage/OWSStorage.m +++ /dev/null @@ -1,1008 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import "OWSStorage.h" -#import "AppContext.h" -#import "NSNotificationCenter+OWS.h" -#import "NSUserDefaults+OWS.h" -#import "OWSBackgroundTask.h" -#import "OWSFileSystem.h" -#import "OWSPrimaryStorage.h" -#import "OWSStorage+Subclass.h" -#import "SSKEnvironment.h" -#import "TSAttachmentStream.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -NSString *const OWSResetStorageNotification = @"OWSResetStorageNotification"; - -static NSString *keychainService = @"TSKeyChainService"; -static NSString *keychainDBLegacyPassphrase = @"TSDatabasePass"; -static NSString *keychainDBCipherKeySpec = @"OWSDatabaseCipherKeySpec"; - -const NSUInteger kDatabasePasswordLength = 30; - -typedef NSData *_Nullable (^LoadDatabaseMetadataBlock)(NSError **_Nullable); -typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void); - -NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_DatabaseExtensionVersionMap"; - -#pragma mark - - -// This macro is only intended to be used within OWSDatabaseConnection. -#define OWSAssertCanReadYDB() \ - do { \ - /* There's no convenient way to enforce until SSKEnvironment is configured. */ \ - if (!SSKEnvironment.hasShared) { \ - return; \ - } \ - if (!self.databaseStorage.canReadFromYdb) { \ - OWSLogError(@"storageMode: %@.", SSKFeatureFlags.storageModeDescription); \ - OWSLogError( \ - @"StorageCoordinatorState: %@.", NSStringFromStorageCoordinatorState(self.storageCoordinator.state)); \ - OWSLogError(@"dataStoreForUI: %@.", NSStringForDataStore(StorageCoordinator.dataStoreForUI)); \ - switch (SSKFeatureFlags.storageModeStrictness) { \ - case StorageModeStrictnessFail: \ - OWSFail(@"Unexpected YDB read."); \ - break; \ - case StorageModeStrictnessFailDebug: \ - OWSFailDebug(@"Unexpected YDB read."); \ - break; \ - case StorageModeStrictnessLog: \ - OWSLogError(@"Unexpected YDB read."); \ - break; \ - } \ - } \ - } while (NO) - -// This macro is only intended to be used within OWSDatabaseConnection. -#define OWSAssertCanWriteYDB() \ - do { \ - /* There's no convenient way to enforce until SSKEnvironment is configured. */ \ - if (!SSKEnvironment.hasShared) { \ - return; \ - } \ - if (!self.databaseStorage.canWriteToYdb) { \ - OWSLogError(@"storageMode: %@.", SSKFeatureFlags.storageModeDescription); \ - OWSLogError( \ - @"StorageCoordinatorState: %@.", NSStringFromStorageCoordinatorState(self.storageCoordinator.state)); \ - OWSLogError(@"dataStoreForUI: %@.", NSStringForDataStore(StorageCoordinator.dataStoreForUI)); \ - switch (SSKFeatureFlags.storageModeStrictness) { \ - case StorageModeStrictnessFail: \ - OWSFail(@"Unexpected YDB write."); \ - break; \ - case StorageModeStrictnessFailDebug: \ - OWSFailDebug(@"Unexpected YDB write."); \ - break; \ - case StorageModeStrictnessLog: \ - OWSLogError(@"Unexpected YDB write."); \ - break; \ - } \ - } \ - } while (NO) - -#pragma mark - - -@interface YapDatabaseConnection () - -- (id)initWithDatabase:(YapDatabase *)database; - -@end - -#pragma mark - - -@implementation OWSDatabaseConnection - -- (id)initWithDatabase:(YapDatabase *)database delegate:(id)delegate -{ - self = [super initWithDatabase:database]; - - if (!self) { - return self; - } - - OWSAssertDebug(delegate); - - self.delegate = delegate; - - return self; -} - -- (void)readWithBlock:(void (^)(YapDatabaseReadTransaction *transaction))block -{ - OWSAssertCanReadYDB(); - - [super readWithBlock:block]; -} - -- (void)asyncReadWithBlock:(void (^)(YapDatabaseReadTransaction *transaction))block -{ - OWSAssertCanReadYDB(); - - [super asyncReadWithBlock:block]; -} - -- (void)asyncReadWithBlock:(void (^)(YapDatabaseReadTransaction *transaction))block - completionBlock:(nullable dispatch_block_t)completionBlock -{ - OWSAssertCanReadYDB(); - - [super asyncReadWithBlock:block completionBlock:completionBlock]; -} - -- (void)asyncReadWithBlock:(void (^)(YapDatabaseReadTransaction *transaction))block - completionQueue:(nullable dispatch_queue_t)completionQueue - completionBlock:(nullable dispatch_block_t)completionBlock -{ - OWSAssertCanReadYDB(); - - [super asyncReadWithBlock:block completionQueue:completionQueue completionBlock:completionBlock]; -} - -// Assert that the database is in a ready state (specifically that any sync database -// view registrations have completed and any async registrations have been started) -// before creating write transactions. -// -// Creating write transactions before the _sync_ database views are registered -// causes YapDatabase to rebuild all of our database views, which is catastrophic. -// Specifically, it causes YDB's "view version" checks to fail. -- (void)readWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block -{ - if (!self.isCleanupConnection) { - OWSAssertCanWriteYDB(); - } - id delegate = self.delegate; - OWSAssertDebug(delegate); - OWSAssertDebug(delegate.areAllRegistrationsComplete); - - OWSBackgroundTask *_Nullable backgroundTask = nil; - if (CurrentAppContext().isMainApp && !CurrentAppContext().isRunningTests) { - backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; - } - [super readWriteWithBlock:block]; - backgroundTask = nil; -} - -- (void)asyncReadWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block -{ - [self asyncReadWriteWithBlock:block completionQueue:NULL completionBlock:NULL]; -} - -- (void)asyncReadWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block - completionBlock:(nullable dispatch_block_t)completionBlock -{ - [self asyncReadWriteWithBlock:block completionQueue:NULL completionBlock:completionBlock]; -} - -- (void)asyncReadWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block - completionQueue:(nullable dispatch_queue_t)completionQueue - completionBlock:(nullable dispatch_block_t)completionBlock -{ - OWSAssertCanWriteYDB(); - id delegate = self.delegate; - OWSAssertDebug(delegate); - OWSAssertDebug(delegate.areAllRegistrationsComplete); - - __block OWSBackgroundTask *_Nullable backgroundTask = nil; - if (CurrentAppContext().isMainApp) { - backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; - } - [super asyncReadWriteWithBlock:block completionQueue:completionQueue completionBlock:^{ - if (completionBlock) { - completionBlock(); - } - backgroundTask = nil; - }]; -} - -@end - -#pragma mark - - -// This class is only used in DEBUG builds. -@interface YapDatabase () - -- (void)addConnection:(YapDatabaseConnection *)connection; - -- (YapDatabaseConnection *)registrationConnection; - -@end - -#pragma mark - - -@interface OWSDatabase () - -@property (atomic, weak) id delegate; - -@end - -#pragma mark - - -@implementation OWSDatabase - -- (id)initWithPath:(NSString *)inPath - serializer:(nullable YapDatabaseSerializer)inSerializer - deserializer:(YapDatabaseDeserializer)inDeserializer - options:(YapDatabaseOptions *)inOptions - delegate:(id)delegate -{ - self = [super initWithPath:inPath serializer:inSerializer deserializer:inDeserializer options:inOptions]; - - if (!self) { - return self; - } - - OWSAssertDebug(delegate); - - self.delegate = delegate; - - return self; -} - -// This clobbers the superclass implementation to include asserts which -// ensure that the database is in a ready state before creating write transactions. -// -// See comments in OWSDatabaseConnection. -- (YapDatabaseConnection *)newConnection -{ - id delegate = self.delegate; - OWSAssertDebug(delegate); - - OWSDatabaseConnection *connection = [[OWSDatabaseConnection alloc] initWithDatabase:self delegate:delegate]; - [self addConnection:connection]; - return connection; -} - -- (YapDatabaseConnection *)registrationConnection -{ - YapDatabaseConnection *connection = [super registrationConnection]; - return connection; -} - -@end - -#pragma mark - - -@interface OWSUnknownDBObject : BaseModel - -@end - -#pragma mark - - -/** - * A default object to return when we can't deserialize an object from YapDB. This can prevent crashes when - * old objects linger after their definition file is removed. The danger is that, the objects can lay in wait - * until the next time a DB extension is added and we necessarily enumerate the entire DB. - */ -@implementation OWSUnknownDBObject - -- (void)encodeWithCoder:(NSCoder *)aCoder -{ - OWSFailDebug(@"Tried to save object from unknown collection"); - - return [super encodeWithCoder:aCoder]; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - self = [super initWithCoder:coder]; - if (!self) { - return self; - } - - return self; -} - -- (void)ydb_saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSFailDebug(@"Tried to save unknown object"); - - // No-op. -} - -- (void)ydb_removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSFailDebug(@"Tried to remove unknown object"); - - // No-op. -} - -@end - -#pragma mark - - -@interface OWSUnarchiverDelegate : NSObject - -@end - -#pragma mark - - -@implementation OWSUnarchiverDelegate - -- (nullable Class)unarchiver:(NSKeyedUnarchiver *)unarchiver - cannotDecodeObjectOfClassName:(NSString *)name - originalClasses:(NSArray *)classNames -{ - if ([name isEqualToString:@"TSRecipient"]) { - OWSLogError(@"Could not decode object: %@", name); - } else { - OWSFailDebug(@"Could not decode object: %@", name); - } - OWSProdCritical([OWSAnalyticsEvents storageErrorCouldNotDecodeClass]); - return [OWSUnknownDBObject class]; -} - -@end - -#pragma mark - - -@interface OWSStorage () - -@property (atomic, nullable) YapDatabase *database; - -@property (nonatomic) NSMutableArray *extensionNames; - -@end - -#pragma mark - - -@implementation OWSStorage - -- (instancetype)init -{ - self = [super init]; - - if (self) { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(resetStorage) - name:OWSResetStorageNotification - object:nil]; - - self.extensionNames = [NSMutableArray new]; - } - - return self; -} - -- (void)dealloc -{ - // Surface memory leaks by logging the deallocation of this class. - OWSLogVerbose(@"Dealloc: %@", self.class); - - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (void)loadDatabase -{ - if (![self tryToLoadDatabase]) { - // Failing to load the database is catastrophic. - // - // The best we can try to do is to discard the current database - // and behave like a clean install. - OWSFailDebug(@"Could not load database"); - OWSProdCritical([OWSAnalyticsEvents storageErrorCouldNotLoadDatabase]); - - // Try to reset app by deleting all databases. - // - // TODO: Possibly clean up all app files. - // [OWSStorage deleteDatabaseFiles]; - - if (![self tryToLoadDatabase]) { - OWSFailDebug(@"Could not load database (second try)"); - OWSProdCritical([OWSAnalyticsEvents storageErrorCouldNotLoadDatabaseSecondAttempt]); - - // Sleep to give analytics events time to be delivered. - [NSThread sleepForTimeInterval:15.0f]; - - OWSFail(@"Failed to initialize database."); - } - } -} - -- (nullable id)dbNotificationObject -{ - OWSAssertDebug(self.database); - - return self.database; -} - -- (BOOL)areAsyncRegistrationsComplete -{ - OWSAbstractMethod(); - - return NO; -} - -- (BOOL)areSyncRegistrationsComplete -{ - OWSAbstractMethod(); - - return NO; -} - -- (BOOL)areAllRegistrationsComplete -{ - return self.areSyncRegistrationsComplete && self.areAsyncRegistrationsComplete; -} - -- (void)runSyncRegistrations -{ - OWSAbstractMethod(); -} - -- (void)runAsyncRegistrationsWithCompletion:(void (^_Nonnull)(void))completion -{ - OWSAbstractMethod(); -} - -+ (void)registerExtensionsWithCompletionBlock:(OWSStorageCompletionBlock)completionBlock -{ - OWSAssertDebug(self.databaseStorage.canLoadYdb); - OWSAssertDebug(completionBlock); - - [self.primaryStorage runSyncRegistrations]; - - [self.primaryStorage runAsyncRegistrationsWithCompletion:^{ - OWSAssertDebug(self.isStorageReady); - - completionBlock(); - }]; -} - -- (YapDatabaseConnection *)registrationConnection -{ - return self.database.registrationConnection; -} - -+ (BOOL)isStorageReady -{ - if (self.databaseStorage.canLoadYdb && !self.primaryStorage.areAllRegistrationsComplete) { - return NO; - } - return YES; -} - -+ (YapDatabaseOptions *)defaultDatabaseOptions -{ - YapDatabaseOptions *options = [[YapDatabaseOptions alloc] init]; - options.corruptAction = YapDatabaseCorruptAction_Fail; - options.enableMultiProcessSupport = YES; - - // We leave a portion of the header decrypted so that iOS will recognize the file - // as a SQLite database. Otherwise, because the database lives in a shared data container, - // and our usage of sqlite's write-ahead logging retains a lock on the database, the OS - // would kill the app/share extension as soon as it is backgrounded. - options.cipherUnencryptedHeaderLength = kSqliteHeaderLength; - - // If we want to migrate to the new cipher defaults in SQLCipher4+ we'll need to do a one time - // migration. See the `PRAGMA cipher_migrate` documentation for details. - // https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_migrate - options.legacyCipherCompatibilityVersion = 3; - - // If any of these asserts fails, we need to verify and update - // OWSDatabaseConverter which assumes the values of these options. - OWSAssertDebug(options.cipherDefaultkdfIterNumber == 0); - OWSAssertDebug(options.kdfIterNumber == 0); - OWSAssertDebug(options.cipherPageSize == 0); - OWSAssertDebug(options.pragmaPageSize == 0); - OWSAssertDebug(options.pragmaJournalSizeLimit == 0); - OWSAssertDebug(options.pragmaMMapSize == 0); - - return options; -} - -- (BOOL)tryToLoadDatabase -{ - __weak OWSStorage *weakSelf = self; - YapDatabaseOptions *options = [self.class defaultDatabaseOptions]; - options.cipherKeySpecBlock = ^{ - // NOTE: It's critical that we don't capture a reference to self - // (e.g. by using OWSAssertDebug()) or this database will contain a - // circular reference and will leak. - OWSStorage *strongSelf = weakSelf; - OWSCAssertDebug(strongSelf); - - // Rather than compute this once and capture the value of the key - // in the closure, we prefer to fetch the key from the keychain multiple times - // in order to keep the key out of application memory. - NSData *databaseKeySpec = [strongSelf databaseKeySpec]; - OWSCAssertDebug(databaseKeySpec.length == kSQLCipherKeySpecLength); - return databaseKeySpec; - }; - - // Sanity checking elsewhere asserts we should only regenerate key specs when - // there is no existing database, so rather than lazily generate in the cipherKeySpecBlock - // we must ensure the keyspec exists before we create the database. - [self ensureDatabaseKeySpecExists]; - - OWSDatabase *database = [[OWSDatabase alloc] initWithPath:[self databaseFilePath] - serializer:nil - deserializer:[[self class] logOnFailureDeserializer] - options:options - delegate:self]; - - if (!database) { - return NO; - } - - _database = database; - - return YES; -} - -/** - * NSCoding sometimes throws exceptions killing our app. We want to log that exception. - **/ -+ (YapDatabaseDeserializer)logOnFailureDeserializer -{ - OWSUnarchiverDelegate *unarchiverDelegate = [OWSUnarchiverDelegate new]; - - return ^id(NSString __unused *collection, NSString __unused *key, NSData *data) { - if (!data || data.length <= 0) { - OWSFailDebug(@"can't deserialize null object: %@", collection); - return [OWSUnknownDBObject new]; - } - - @try { - NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; - unarchiver.delegate = unarchiverDelegate; - return [unarchiver decodeObjectForKey:@"root"]; - } @catch (NSException *exception) { - // Sync log in case we bail. - OWSFailDebug(@"error deserializing object: %@, %@", collection, exception); - OWSProdCritical([OWSAnalyticsEvents storageErrorDeserialization]); - @throw exception; - } - }; -} - -- (YapDatabaseConnection *)newDatabaseConnection -{ - YapDatabaseConnection *dbConnection = self.database.newConnection; - if (!dbConnection) { - OWSFail(@"Storage could not open new database connection."); - } - return dbConnection; -} - -#pragma mark - Extension Registration - -+ (void)incrementVersionOfDatabaseExtension:(NSString *)extensionName -{ - OWSLogError(@"%@", extensionName); - - // Don't increment version of a given extension more than once - // per launch. - static NSMutableSet *incrementedViewSet = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - incrementedViewSet = [NSMutableSet new]; - }); - @synchronized(incrementedViewSet) { - if ([incrementedViewSet containsObject:extensionName]) { - OWSLogInfo(@"Ignoring redundant increment: %@", extensionName); - return; - } - [incrementedViewSet addObject:extensionName]; - } - - NSUserDefaults *appUserDefaults = [NSUserDefaults appUserDefaults]; - OWSAssertDebug(appUserDefaults); - NSMutableDictionary *_Nullable versionMap = - [[appUserDefaults valueForKey:kNSUserDefaults_DatabaseExtensionVersionMap] mutableCopy]; - if (!versionMap) { - versionMap = [NSMutableDictionary new]; - } - NSNumber *_Nullable versionSuffix = versionMap[extensionName]; - versionMap[extensionName] = @(versionSuffix.intValue + 1); - [appUserDefaults setValue:versionMap forKey:kNSUserDefaults_DatabaseExtensionVersionMap]; - [appUserDefaults synchronize]; -} - -- (nullable NSString *)appendSuffixToDatabaseExtensionVersionIfNecessary:(nullable NSString *)versionTag - extensionName:(NSString *)extensionName -{ - OWSAssertIsOnMainThread(); - - NSUserDefaults *appUserDefaults = [NSUserDefaults appUserDefaults]; - OWSAssertDebug(appUserDefaults); - NSDictionary *_Nullable versionMap = - [appUserDefaults valueForKey:kNSUserDefaults_DatabaseExtensionVersionMap]; - NSNumber *_Nullable versionSuffix = versionMap[extensionName]; - - if (versionSuffix) { - NSString *result = - [NSString stringWithFormat:@"%@.%@", (versionTag.length < 1 ? @"0" : versionTag), versionSuffix]; - OWSLogWarn(@"database extension version: %@ + %@ -> %@", versionTag, versionSuffix, result); - return result; - } - return versionTag; -} - -- (YapDatabaseExtension *)updateExtensionVersion:(YapDatabaseExtension *)extension withName:(NSString *)extensionName -{ - OWSAssertDebug(extension); - OWSAssertDebug(extensionName.length > 0); - - if ([extension isKindOfClass:[YapDatabaseAutoView class]]) { - YapDatabaseAutoView *databaseView = (YapDatabaseAutoView *)extension; - YapDatabaseAutoView *databaseViewCopy = [[YapDatabaseAutoView alloc] - initWithGrouping:databaseView.grouping - sorting:databaseView.sorting - versionTag:[self appendSuffixToDatabaseExtensionVersionIfNecessary:databaseView.versionTag - extensionName:extensionName] - options:databaseView.options]; - return databaseViewCopy; - } else if ([extension isKindOfClass:[YapDatabaseSecondaryIndex class]]) { - YapDatabaseSecondaryIndex *secondaryIndex = (YapDatabaseSecondaryIndex *)extension; - OWSAssertDebug(secondaryIndex->setup); - OWSAssertDebug(secondaryIndex->handler); - YapDatabaseSecondaryIndex *secondaryIndexCopy = [[YapDatabaseSecondaryIndex alloc] - initWithSetup:secondaryIndex->setup - handler:secondaryIndex->handler - versionTag:[self appendSuffixToDatabaseExtensionVersionIfNecessary:secondaryIndex.versionTag - extensionName:extensionName] - options:secondaryIndex->options]; - return secondaryIndexCopy; - } else if ([extension isKindOfClass:[YapDatabaseFullTextSearch class]]) { - YapDatabaseFullTextSearch *fullTextSearch = (YapDatabaseFullTextSearch *)extension; - - NSString *versionTag = [self appendSuffixToDatabaseExtensionVersionIfNecessary:fullTextSearch.versionTag extensionName:extensionName]; - YapDatabaseFullTextSearch *fullTextSearchCopy = - [[YapDatabaseFullTextSearch alloc] initWithColumnNames:fullTextSearch->columnNames.array - options:fullTextSearch->options - handler:fullTextSearch->handler - ftsVersion:fullTextSearch->ftsVersion - versionTag:versionTag]; - - return fullTextSearchCopy; - } else if ([extension isKindOfClass:[YapDatabaseCrossProcessNotification class]]) { - // versionTag doesn't matter for YapDatabaseCrossProcessNotification. - return extension; - } else { - // This method needs to be able to update the versionTag of all extensions. - // If we start using other extension types, we need to modify this method to - // handle them as well. - OWSFailDebug(@"Unknown extension type: %@", [extension class]); - - return extension; - } -} - -- (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName -{ - extension = [self updateExtensionVersion:extension withName:extensionName]; - - OWSAssertDebug(![self.extensionNames containsObject:extensionName]); - [self.extensionNames addObject:extensionName]; - - return [self.database registerExtension:extension withName:extensionName]; -} - -- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension - withName:(NSString *)extensionName -{ - [self asyncRegisterExtension:extension withName:extensionName completion:nil]; -} - -- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension - withName:(NSString *)extensionName - completion:(nullable dispatch_block_t)completion -{ - extension = [self updateExtensionVersion:extension withName:extensionName]; - - OWSAssertDebug(![self.extensionNames containsObject:extensionName]); - [self.extensionNames addObject:extensionName]; - - [self.database asyncRegisterExtension:extension - withName:extensionName - completionBlock:^(BOOL ready) { - if (!ready) { - OWSFailDebug(@"asyncRegisterExtension failed: %@", extensionName); - } else { - if (!CurrentAppContext().isRunningTests) { - OWSLogVerbose(@"asyncRegisterExtension succeeded: %@", extensionName); - } - } - - dispatch_async(dispatch_get_main_queue(), ^{ - if (completion) { - completion(); - } - }); - }]; -} - -- (nullable id)registeredExtension:(NSString *)extensionName -{ - return [self.database registeredExtension:extensionName]; -} - -- (NSArray *)registeredExtensionNames -{ - return [self.extensionNames copy]; -} - -#pragma mark - Password - -+ (void)deleteDatabaseFiles -{ - [OWSFileSystem deleteFileIfExists:[OWSPrimaryStorage legacyDatabaseFilePath]]; - [OWSFileSystem deleteFileIfExists:[OWSPrimaryStorage legacyDatabaseFilePath_SHM]]; - [OWSFileSystem deleteFileIfExists:[OWSPrimaryStorage legacyDatabaseFilePath_WAL]]; - [OWSFileSystem deleteFileIfExists:[OWSPrimaryStorage sharedDataDatabaseFilePath]]; - [OWSFileSystem deleteFileIfExists:[OWSPrimaryStorage sharedDataDatabaseFilePath_SHM]]; - [OWSFileSystem deleteFileIfExists:[OWSPrimaryStorage sharedDataDatabaseFilePath_WAL]]; - // NOTE: It's NOT safe to delete OWSPrimaryStorage.legacyDatabaseDirPath - // which is the app document dir. - [OWSFileSystem deleteContentsOfDirectory:OWSPrimaryStorage.sharedDataDatabaseDirPath]; -} - -- (void)closeStorageForTests -{ - [self resetStorage]; - - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (void)resetStorage -{ - self.database = nil; - - [OWSStorage deleteDatabaseFiles]; -} - -+ (void)resetAllStorage -{ - OWSLogInfo(@""); - - [[NSNotificationCenter defaultCenter] postNotificationName:OWSResetStorageNotification object:nil]; - - // This might be redundant but in the spirit of thoroughness... - [self deleteDatabaseFiles]; - - [self deleteDBKeys]; - - if (CurrentAppContext().isMainApp) { - [TSAttachmentStream deleteAttachmentsFromDisk]; - } - - // TODO: Delete Profiles on Disk? -} - -#pragma mark - Password - -- (NSString *)databaseFilePath -{ - OWSAbstractMethod(); - - return @""; -} - -- (NSString *)databaseFilePath_SHM -{ - OWSAbstractMethod(); - - return @""; -} - -- (NSString *)databaseFilePath_WAL -{ - OWSAbstractMethod(); - - return @""; -} - -#pragma mark - Keychain - -+ (BOOL)isDatabasePasswordAccessible -{ - NSError *error; - NSData *cipherKeySpec = [self tryToLoadDatabaseCipherKeySpec:&error]; - - if (cipherKeySpec && !error) { - return YES; - } - - if (error) { - OWSLogWarn(@"Database key couldn't be accessed: %@", error.localizedDescription); - } - - return NO; -} - -+ (nullable NSData *)tryToLoadDatabaseLegacyPassphrase:(NSError **)errorHandle -{ - return [self tryToLoadKeyChainValue:keychainDBLegacyPassphrase errorHandle:errorHandle]; -} - -+ (nullable NSData *)tryToLoadDatabaseCipherKeySpec:(NSError **)errorHandle -{ - NSData *_Nullable data = [self tryToLoadKeyChainValue:keychainDBCipherKeySpec errorHandle:errorHandle]; - OWSAssertDebug(!data || data.length == kSQLCipherKeySpecLength); - - return data; -} - -+ (void)storeDatabaseCipherKeySpec:(NSData *)cipherKeySpecData -{ - OWSAssertDebug(cipherKeySpecData.length == kSQLCipherKeySpecLength); - - [self storeKeyChainValue:cipherKeySpecData keychainKey:keychainDBCipherKeySpec]; -} - -+ (void)removeLegacyPassphrase -{ - OWSLogInfo(@"removing legacy passphrase"); - - NSError *_Nullable error; - BOOL result = [CurrentAppContext().keychainStorage removeWithService:keychainService - key:keychainDBLegacyPassphrase - error:&error]; - if (error || !result) { - OWSFailDebug(@"could not remove legacy passphrase."); - } -} - -- (void)ensureDatabaseKeySpecExists -{ - NSError *error; - NSData *_Nullable keySpec = [[self class] tryToLoadDatabaseCipherKeySpec:&error]; - - if (error || (keySpec.length != kSQLCipherKeySpecLength)) { - // Because we use kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, - // the keychain will be inaccessible after device restart until - // device is unlocked for the first time. If the app receives - // a push notification, we won't be able to access the keychain to - // process that notification, so we should just terminate by throwing - // an uncaught exception. - NSString *errorDescription = [NSString - stringWithFormat:@"CipherKeySpec inaccessible. New install or no unlock since device restart? Error: %@", - error]; - if (CurrentAppContext().isMainApp) { - UIApplicationState applicationState = CurrentAppContext().reportedApplicationState; - errorDescription = [errorDescription - stringByAppendingFormat:@", ApplicationState: %@", NSStringForUIApplicationState(applicationState)]; - } - OWSLogError(@"%@", errorDescription); - [DDLog flushLog]; - - if (CurrentAppContext().isMainApp) { - if (CurrentAppContext().isInBackground) { - // Rather than crash here, we should have already detected the situation earlier - // and exited gracefully (in the app delegate) using isDatabasePasswordAccessible. - // This is a last ditch effort to avoid blowing away the user's database. - [self raiseKeySpecInaccessibleExceptionWithErrorDescription:errorDescription]; - } - } else { - [self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec inaccessible; not main app."]; - } - - // At this point, either: - // - // * This is a new install so there's no existing password to retrieve. - // * The keychain has become corrupt. - BOOL doesDBExist = [NSFileManager.defaultManager fileExistsAtPath:[self databaseFilePath]]; - if (doesDBExist) { - OWSFail(@"Could not load database metadata"); - OWSProdCritical([OWSAnalyticsEvents storageErrorCouldNotLoadDatabaseSecondAttempt]); - } - - keySpec = [Randomness generateRandomBytes:(int)kSQLCipherKeySpecLength]; - [[self class] storeDatabaseCipherKeySpec:keySpec]; - } -} - -- (NSData *)databaseKeySpec -{ - NSError *error; - NSData *_Nullable keySpec = [[self class] tryToLoadDatabaseCipherKeySpec:&error]; - - if (error) { - OWSLogError(@"failed to fetch databaseKeySpec with error: %@", error); - [self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec inaccessible"]; - } - - if (keySpec.length != kSQLCipherKeySpecLength) { - OWSLogError(@"keyspec had length: %lu", (unsigned long)keySpec.length); - [self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec invalid"]; - } - - return keySpec; -} - -- (void)raiseKeySpecInaccessibleExceptionWithErrorDescription:(NSString *)errorDescription -{ - OWSAssertDebug(CurrentAppContext().isMainApp && CurrentAppContext().isInBackground); - - // Sleep to give analytics events time to be delivered. - [NSThread sleepForTimeInterval:5.0f]; - - // Presumably this happened in response to a push notification. It's possible that the keychain is corrupted - // but it could also just be that the user hasn't yet unlocked their device since our password is - // kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly - OWSFail(@"%@", errorDescription); -} - -+ (void)deleteDBKeys -{ - NSError *_Nullable error; - BOOL result = [CurrentAppContext().keychainStorage removeWithService:keychainService - key:keychainDBLegacyPassphrase - error:&error]; - if (error || !result) { - OWSFailDebug(@"could not remove legacy passphrase."); - } - result = [CurrentAppContext().keychainStorage removeWithService:keychainService - key:keychainDBCipherKeySpec - error:&error]; - if (error || !result) { - OWSFailDebug(@"could not remove cipher key spec."); - } -} - -- (unsigned long long)databaseFileSize -{ - return [OWSFileSystem fileSizeOfPath:self.databaseFilePath].unsignedLongLongValue; -} - -- (unsigned long long)databaseWALFileSize -{ - return [OWSFileSystem fileSizeOfPath:self.databaseFilePath_WAL].unsignedLongLongValue; -} - -- (unsigned long long)databaseSHMFileSize -{ - return [OWSFileSystem fileSizeOfPath:self.databaseFilePath_SHM].unsignedLongLongValue; -} - -+ (nullable NSData *)tryToLoadKeyChainValue:(NSString *)keychainKey errorHandle:(NSError **)errorHandle -{ - OWSAssertDebug(keychainKey.length > 0); - OWSAssertDebug(errorHandle); - - NSData *_Nullable data = - [CurrentAppContext().keychainStorage dataForService:keychainService key:keychainKey error:errorHandle]; - if (*errorHandle || !data) { - OWSLogWarn(@"could not load keychain value."); - } - return data; -} - -+ (void)storeKeyChainValue:(NSData *)data keychainKey:(NSString *)keychainKey -{ - OWSAssertDebug(keychainKey.length > 0); - OWSAssertDebug(data.length > 0); - - NSError *error; - BOOL success = - [CurrentAppContext().keychainStorage setWithData:data service:keychainService key:keychainKey error:&error]; - if (!success || error) { - OWSFailDebug(@"Could not store database metadata"); - OWSProdCritical([OWSAnalyticsEvents storageErrorCouldNotStoreKeychainValue]); - - // Sleep to give analytics events time to be delivered. - [NSThread sleepForTimeInterval:15.0f]; - - OWSFail(@"Setting keychain value failed with error: %@", error); - } else { - OWSLogWarn(@"Successfully set new keychain value."); - } -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/SSKIncrementingIdFinder.swift b/SignalServiceKit/src/Storage/SSKIncrementingIdFinder.swift deleted file mode 100644 index 84e6a33afe..0000000000 --- a/SignalServiceKit/src/Storage/SSKIncrementingIdFinder.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - -@objc -public class SSKIncrementingIdFinder: NSObject { - - @objc - public static let collectionName = "IncrementingIdCollection" - - @objc - public class func previousId(key: String, transaction: YapDatabaseReadTransaction) -> UInt64 { - let previousId: UInt64 = transaction.object(forKey: key, inCollection: collectionName) as? UInt64 ?? 0 - return previousId - } - - @objc - public class func nextId(key: String, transaction: YapDatabaseReadWriteTransaction) -> UInt64 { - let previousId: UInt64 = transaction.object(forKey: key, inCollection: collectionName) as? UInt64 ?? 0 - let nextId: UInt64 = previousId + 1 - - transaction.setObject(nextId, forKey: key, inCollection: collectionName) - return nextId - } -} diff --git a/SignalServiceKit/src/Storage/SSKMessageSenderJobRecord.m b/SignalServiceKit/src/Storage/SSKMessageSenderJobRecord.m index 2828e44e9a..a20a41e30b 100644 --- a/SignalServiceKit/src/Storage/SSKMessageSenderJobRecord.m +++ b/SignalServiceKit/src/Storage/SSKMessageSenderJobRecord.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // #import "SSKMessageSenderJobRecord.h" @@ -39,12 +39,7 @@ NS_ASSUME_NONNULL_BEGIN return nil; } - // This path gets hit during the YDB->GRDB migration *tests*, at which point - // it's unsafe to assume we have a GRDB transaction. We can safely skip this - // step during the tests when we don't. - if (!transaction.isYapRead) { - _isMediaMessage = [message hasMediaAttachmentsWithTransaction:transaction.unwrapGrdbRead]; - } + _isMediaMessage = [message hasMediaAttachmentsWithTransaction:transaction.unwrapGrdbRead]; _invisibleMessage = nil; } else { diff --git a/SignalServiceKit/src/Storage/StorageCoordinator.h b/SignalServiceKit/src/Storage/StorageCoordinator.h index d0e3c22e11..48c2e52603 100644 --- a/SignalServiceKit/src/Storage/StorageCoordinator.h +++ b/SignalServiceKit/src/Storage/StorageCoordinator.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // NS_ASSUME_NONNULL_BEGIN @@ -9,18 +9,12 @@ NS_ASSUME_NONNULL_BEGIN extern NSString *const StorageIsReadyNotification; typedef NS_CLOSED_ENUM(NSUInteger, DataStore) { - DataStoreYdb, DataStoreGrdb, }; NSString *NSStringForDataStore(DataStore value); typedef NS_CLOSED_ENUM(NSUInteger, StorageCoordinatorState) { - // GRDB TODO: Remove .ydb and ydbTests once we ship GRDB to production. - StorageCoordinatorStateYDB, - StorageCoordinatorStateBeforeYDBToGRDBMigration, - StorageCoordinatorStateDuringYDBToGRDBMigration, StorageCoordinatorStateGRDB, - StorageCoordinatorStateYDBTests, StorageCoordinatorStateGRDBTests, }; NSString *NSStringFromStorageCoordinatorState(StorageCoordinatorState value); @@ -31,19 +25,11 @@ NSString *NSStringFromStorageCoordinatorState(StorageCoordinatorState value); @property (atomic, readonly) StorageCoordinatorState state; -@property (atomic, readonly) BOOL isMigrating; - @property (atomic, readonly) BOOL isStorageReady; - (instancetype)init; -// These methods should only be called by the migration itself. -- (void)migrationYDBToGRDBWillBegin; -- (void)migrationYDBToGRDBDidComplete; - -@property (class, nonatomic, readonly) BOOL hasYdbFile; @property (class, nonatomic, readonly) BOOL hasGrdbFile; -@property (class, nonatomic, readonly) BOOL hasUnmigratedYdbFile; @property (class, nonatomic, readonly) BOOL hasInvalidDatabaseVersion; @@ -55,11 +41,6 @@ NSString *NSStringFromStorageCoordinatorState(StorageCoordinatorState value); - (BOOL)isDatabasePasswordAccessible; -#ifdef TESTABLE_BUILD -- (void)useGRDBForTests; -- (void)useYDBForTests; -#endif - - (void)markStorageSetupAsComplete; @end diff --git a/SignalServiceKit/src/Storage/StorageCoordinator.m b/SignalServiceKit/src/Storage/StorageCoordinator.m index 1c742721e4..d9c73e0fc1 100644 --- a/SignalServiceKit/src/Storage/StorageCoordinator.m +++ b/SignalServiceKit/src/Storage/StorageCoordinator.m @@ -5,8 +5,8 @@ #import "StorageCoordinator.h" #import "AppReadiness.h" #import -#import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -15,16 +15,8 @@ NSString *const StorageIsReadyNotification = @"StorageIsReadyNotification"; NSString *NSStringFromStorageCoordinatorState(StorageCoordinatorState value) { switch (value) { - case StorageCoordinatorStateYDB: - return @"StorageCoordinatorStateYDB"; - case StorageCoordinatorStateBeforeYDBToGRDBMigration: - return @"StorageCoordinatorStateBeforeYDBToGRDBMigration"; - case StorageCoordinatorStateDuringYDBToGRDBMigration: - return @"StorageCoordinatorStateDuringYDBToGRDBMigration"; case StorageCoordinatorStateGRDB: return @"StorageCoordinatorStateGRDB"; - case StorageCoordinatorStateYDBTests: - return @"StorageCoordinatorStateYDBTests"; case StorageCoordinatorStateGRDBTests: return @"StorageCoordinatorStateGRDBTests"; } @@ -33,8 +25,6 @@ NSString *NSStringFromStorageCoordinatorState(StorageCoordinatorState value) NSString *NSStringForDataStore(DataStore value) { switch (value) { - case DataStoreYdb: - return @"DataStoreYdb"; case DataStoreGrdb: return @"DataStoreGrdb"; } @@ -78,8 +68,7 @@ NSString *NSStringForDataStore(DataStore value) + (BOOL)hasYdbFile { - NSString *ydbFilePath = OWSPrimaryStorage.sharedDataDatabaseFilePath; - BOOL hasYdbFile = [OWSFileSystem fileOrFolderExistsAtPath:ydbFilePath]; + BOOL hasYdbFile = YDBStorage.hasAnyYdbFile; if (hasYdbFile && !SSKPreferences.didEverUseYdb) { [SSKPreferences setDidEverUseYdb:YES]; @@ -94,27 +83,8 @@ NSString *NSStringForDataStore(DataStore value) return [OWSFileSystem fileOrFolderExistsAtPath:grdbFilePath]; } -+ (BOOL)hasUnmigratedYdbFile -{ - return self.hasYdbFile && ![SSKPreferences isYdbMigrated]; -} - + (BOOL)hasInvalidDatabaseVersion { - BOOL prefersYdb = SSKFeatureFlags.storageMode == StorageModeYdbForAll; - BOOL willUseYdb = StorageCoordinator.dataStoreForUI == DataStoreYdb; - - BOOL hasValidGrdb = self.hasGrdbFile; - if (self.hasUnmigratedYdbFile) { - hasValidGrdb = NO; - } - - // A check to avoid trying to revert to YDB when we've already migrated to GRDB. - if ((prefersYdb || willUseYdb) && hasValidGrdb) { - OWSFailDebug(@"Reverting to YDB."); - return YES; - } - if (SSKPreferences.hasUnknownGRDBSchema) { OWSFailDebug(@"Unknown GRDB schema."); return YES; @@ -128,13 +98,6 @@ NSString *NSStringForDataStore(DataStore value) return self.state; } -- (BOOL)isMigrating -{ - StorageCoordinatorState state = self.state; - return (state == StorageCoordinatorStateBeforeYDBToGRDBMigration - || state == StorageCoordinatorStateDuringYDBToGRDBMigration); -} - + (DataStore)dataStoreForUI { // Computing dataStoreForUI is slightly expensive. @@ -150,95 +113,15 @@ NSString *NSStringForDataStore(DataStore value) + (DataStore)computeDataStoreForUI { - // NOTE: By now, any move of YDB from the "app container" - // to the "shared container" should be complete, so - // we can ignore the "legacy" database files. - BOOL hasYdbFile = self.hasYdbFile; - BOOL hasGrdbFile = self.hasGrdbFile; - BOOL hasUnmigratedYdbFile = self.hasUnmigratedYdbFile; - BOOL isNewUser = !hasYdbFile && !hasGrdbFile; - - // In the GRDB-possible modes, avoid migrations in certain cases. - switch (SSKFeatureFlags.storageMode) { - case StorageModeYdbForAll: - break; - case StorageModeGrdbForAlreadyMigrated: - case StorageModeGrdbForLegacyUsersOnly: - case StorageModeGrdbForNewUsersOnly: - case StorageModeGrdbForAll: - case StorageModeGrdbThrowawayIfMigrating: - if (CurrentAppContext().isRunningTests) { - // Do nothing. - } else if (hasUnmigratedYdbFile) { - if (!CurrentAppContext().canPresentNotifications) { - // Don't migrate the database in an app extension - // unless it can present notifications. - OWSFail(@"Avoiding YDB-to-GRDB migration in app extension."); - } - if (CurrentAppContext().mainApplicationStateOnLaunch == UIApplicationStateBackground) { - OWSLogInfo(@"Avoiding YDB-to-GRDB migration in background."); - // If we are migrating the database and the app was launched into the background, - // show the "GRDB migration" notification in case the migration fails. - [self showGRDBMigrationNotification]; - } - } - break; - case StorageModeYdbTests: - case StorageModeGrdbTests: - break; - } - - switch (SSKFeatureFlags.storageMode) { - case StorageModeYdbForAll: - return DataStoreYdb; - case StorageModeGrdbForAlreadyMigrated: - if (isNewUser) { - // New users should use YDB. - return DataStoreYdb; - } else if (hasUnmigratedYdbFile) { - // Existing users should use YDB. - return DataStoreYdb; - } else { - // Only users who have already migrated to GRDB should use GRDB. - return DataStoreGrdb; - } - case StorageModeGrdbForLegacyUsersOnly: - if (isNewUser) { - // New users should use YDB. - return DataStoreYdb; - } else { - return DataStoreGrdb; - } - case StorageModeGrdbForNewUsersOnly: - if (isNewUser) { - // New users should use GRDB. - return DataStoreGrdb; - } else if (hasUnmigratedYdbFile) { - return DataStoreYdb; - } else { - return DataStoreGrdb; - } - case StorageModeGrdbForAll: - case StorageModeGrdbThrowawayIfMigrating: - return DataStoreGrdb; - case StorageModeYdbTests: - return DataStoreYdb; - case StorageModeGrdbTests: - return DataStoreGrdb; - } + // TODO: + return DataStoreGrdb; } + (BOOL)isReadyForShareExtension { OWSAssertDebug(SSKFeatureFlags.storageMode == StorageModeGrdbForAll); - // NOTE: By now, any move of YDB from the "app container" - // to the "shared container" should be complete, so - // we can ignore the "legacy" database files. - BOOL hasUnmigratedYdbFile = self.hasUnmigratedYdbFile; - OWSLogInfo(@"hasUnmigratedYdbFile: %d", hasUnmigratedYdbFile); - - return !hasUnmigratedYdbFile; + return true; } + (void)showGRDBMigrationNotification @@ -271,42 +154,23 @@ NSString *NSStringForDataStore(DataStore value) BOOL hasGrdbFile = self.class.hasGrdbFile; OWSLogInfo(@"hasGrdbFile: %d", hasGrdbFile); - BOOL hasUnmigratedYdbFile = self.class.hasUnmigratedYdbFile; - OWSLogInfo(@"hasUnmigratedYdbFile: %d", hasUnmigratedYdbFile); - OWSLogInfo(@"didEverUseYdb: %d", SSKPreferences.didEverUseYdb); switch (SSKFeatureFlags.storageMode) { - case StorageModeYdbForAll: case StorageModeGrdbForAll: - case StorageModeGrdbForAlreadyMigrated: - case StorageModeGrdbForLegacyUsersOnly: - case StorageModeGrdbForNewUsersOnly: - case StorageModeGrdbThrowawayIfMigrating: - if (self.dataStoreForUI == DataStoreYdb) { - self.state = StorageCoordinatorStateYDB; - } else { - if (SSKFeatureFlags.storageMode == StorageModeGrdbThrowawayIfMigrating) { - // Clear flag to force migration. - [SSKPreferences setIsYdbMigrated:NO]; - } + self.state = StorageCoordinatorStateGRDB; - if (hasUnmigratedYdbFile) { - self.state = StorageCoordinatorStateBeforeYDBToGRDBMigration; - - // We might want to delete any existing GRDB database - // files here, since they represent an incomplete - // previous migration and might cause problems. - [self.databaseStorage deleteGrdbFiles]; - } else { - self.state = StorageCoordinatorStateGRDB; - - [self removeYdbFiles]; - } + if (hasYdbFile) { + [SSKPreferences setDidEverUseYdb:YES]; + [SSKPreferences setDidDropYdb:YES]; } - break; - case StorageModeYdbTests: - self.state = StorageCoordinatorStateYDBTests; + + [AppReadiness + runNowOrWhenAppDidBecomeReadyAsync:^{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + ^{ [YDBStorage deleteYDBStorage]; }); + } + label:@"StorageCoordinator.configure"]; break; case StorageModeGrdbTests: self.state = StorageCoordinatorStateGRDBTests; @@ -316,68 +180,9 @@ NSString *NSStringForDataStore(DataStore value) OWSLogInfo(@"state: %@", NSStringFromStorageCoordinatorState(self.state)); } -- (void)migrationYDBToGRDBWillBegin -{ - // These are crashing asserts. - OWSAssert(self.state == StorageCoordinatorStateBeforeYDBToGRDBMigration); - - self.state = StorageCoordinatorStateDuringYDBToGRDBMigration; - - [self.databaseStorage logAllFileSizes]; - - OWSLogInfo(@"state: %@", NSStringFromStorageCoordinatorState(self.state)); -} - -- (void)migrationYDBToGRDBDidComplete -{ - // These are crashing asserts. - OWSAssert(self.state == StorageCoordinatorStateDuringYDBToGRDBMigration); - - self.state = StorageCoordinatorStateGRDB; - - OWSLogInfo(@"state: %@", NSStringFromStorageCoordinatorState(self.state)); - - [self.databaseStorage logAllFileSizes]; -} - - (BOOL)isDatabasePasswordAccessible { - if (self.databaseStorage.canLoadYdb) { - if (![OWSPrimaryStorage isDatabasePasswordAccessible]) { - return NO; - } - } - if (self.databaseStorage.canLoadGrdb) { - if (![GRDBDatabaseStorageAdapter isKeyAccessible]) { - return NO; - } - } - return YES; -} - -#ifdef TESTABLE_BUILD -- (void)useGRDBForTests -{ - self.state = StorageCoordinatorStateGRDBTests; - _dataStoreForUI = DataStoreGrdb; -} - -- (void)useYDBForTests -{ - self.state = StorageCoordinatorStateYDBTests; - _dataStoreForUI = DataStoreYdb; -} -#endif - -- (void)removeYdbFiles -{ - if (SSKFeatureFlags.storageMode == StorageModeGrdbThrowawayIfMigrating) { - // Don't clean up YDB; we're in throwaway mode. - return; - } - - [OWSStorage deleteDatabaseFiles]; - [OWSStorage deleteDBKeys]; + return [GRDBDatabaseStorageAdapter isKeyAccessible]; } - (void)markStorageSetupAsComplete @@ -402,12 +207,6 @@ NSString *NSStringForDataStore(DataStore value) - (BOOL)isStorageReady { switch (self.state) { - case StorageCoordinatorStateYDB: - case StorageCoordinatorStateYDBTests: - return [OWSStorage isStorageReady] && self.isStorageSetupComplete; - case StorageCoordinatorStateBeforeYDBToGRDBMigration: - case StorageCoordinatorStateDuringYDBToGRDBMigration: - return NO; case StorageCoordinatorStateGRDB: case StorageCoordinatorStateGRDBTests: return self.isStorageSetupComplete; diff --git a/SignalServiceKit/src/Storage/TSDatabaseSecondaryIndexes.h b/SignalServiceKit/src/Storage/TSDatabaseSecondaryIndexes.h deleted file mode 100644 index f2e377654a..0000000000 --- a/SignalServiceKit/src/Storage/TSDatabaseSecondaryIndexes.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface TSDatabaseSecondaryIndexes : NSObject - -+ (NSString *)registerTimeStampIndexExtensionName; - -+ (YapDatabaseSecondaryIndex *)registerTimeStampIndex; - -+ (void)enumerateMessagesWithTimestamp:(uint64_t)timestamp - withBlock:(void (^)(NSString *collection, NSString *key, BOOL *stop))block - usingTransaction:(YapDatabaseReadTransaction *)transaction; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/TSDatabaseSecondaryIndexes.m b/SignalServiceKit/src/Storage/TSDatabaseSecondaryIndexes.m deleted file mode 100644 index d31c677d94..0000000000 --- a/SignalServiceKit/src/Storage/TSDatabaseSecondaryIndexes.m +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "TSDatabaseSecondaryIndexes.h" -#import "OWSStorage.h" -#import "TSInteraction.h" - -NS_ASSUME_NONNULL_BEGIN - -#define TSTimeStampSQLiteIndex @"messagesTimeStamp" - -@implementation TSDatabaseSecondaryIndexes - -+ (NSString *)registerTimeStampIndexExtensionName -{ - return @"idx"; -} - -+ (YapDatabaseSecondaryIndex *)registerTimeStampIndex { - YapDatabaseSecondaryIndexSetup *setup = [[YapDatabaseSecondaryIndexSetup alloc] init]; - [setup addColumn:TSTimeStampSQLiteIndex withType:YapDatabaseSecondaryIndexTypeReal]; - - YapDatabaseSecondaryIndexWithObjectBlock block = - ^(YapDatabaseReadTransaction *transaction, NSMutableDictionary *dict, NSString *collection, NSString *key, id object) { - - if ([object isKindOfClass:[TSInteraction class]]) { - TSInteraction *interaction = (TSInteraction *)object; - - [dict setObject:@(interaction.timestamp) forKey:TSTimeStampSQLiteIndex]; - } - }; - - YapDatabaseSecondaryIndexHandler *handler = [YapDatabaseSecondaryIndexHandler withObjectBlock:block]; - - YapDatabaseSecondaryIndex *secondaryIndex = - [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler versionTag:nil]; - - return secondaryIndex; -} - - -+ (void)enumerateMessagesWithTimestamp:(uint64_t)timestamp - withBlock:(void (^)(NSString *collection, NSString *key, BOOL *stop))block - usingTransaction:(YapDatabaseReadTransaction *)transaction -{ - NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ = %lld", TSTimeStampSQLiteIndex, timestamp]; - YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString]; - [[transaction ext:[self registerTimeStampIndexExtensionName]] enumerateKeysMatchingQuery:query usingBlock:block]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/TSDatabaseView.h b/SignalServiceKit/src/Storage/TSDatabaseView.h deleted file mode 100644 index cba1e1cfef..0000000000 --- a/SignalServiceKit/src/Storage/TSDatabaseView.h +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. -// - -#import "OWSStorage.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -// POST GRDB TODO - Some of these views can be removed. -extern NSString *const TSInboxGroup; -extern NSString *const TSArchiveGroup; -extern NSString *const TSUnreadIncomingMessagesGroup; -extern NSString *const TSSecondaryDevicesGroup; - -extern NSString *const TSThreadDatabaseViewExtensionName; - -extern NSString *const TSMessageDatabaseViewExtensionName; -extern NSString *const TSMessageDatabaseViewExtensionName_Legacy; - -extern NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName; -extern NSString *const TSThreadSpecialMessagesDatabaseViewExtensionName; -extern NSString *const TSIncompleteViewOnceMessagesDatabaseViewExtensionName; -extern NSString *const TSIncompleteViewOnceMessagesGroup; - -extern NSString *const TSInteractionsBySortIdGroup; -extern NSString *const TSInteractionsBySortIdDatabaseViewExtensionName; - -extern NSString *const TSLazyRestoreAttachmentsGroup; -extern NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName; - -@interface TSDatabaseView : NSObject - -+ (instancetype)new NS_UNAVAILABLE; -- (instancetype)init NS_UNAVAILABLE; - -#pragma mark - Views - -// POST GRDB TODO: Remove these methods? - -+ (id)threadOutgoingMessageDatabaseView:(YapDatabaseReadTransaction *)transaction; - -+ (id)threadSpecialMessagesDatabaseView:(YapDatabaseReadTransaction *)transaction; - -+ (id)incompleteViewOnceMessagesDatabaseView:(YapDatabaseReadTransaction *)transaction; - -#pragma mark - Registration - -+ (void)registerCrossProcessNotifier:(OWSStorage *)storage; - -// This method must be called _AFTER_ asyncRegisterThreadInteractionsDatabaseView. -+ (void)asyncRegisterThreadDatabaseView:(OWSStorage *)storage; - -+ (void)asyncRegisterThreadInteractionsDatabaseView:(OWSStorage *)storage; -+ (void)asyncRegisterLegacyThreadInteractionsDatabaseView:(OWSStorage *)storage; -+ (void)asyncRegisterInteractionsBySortIdDatabaseView:(OWSStorage *)storage; - -+ (void)asyncRegisterThreadOutgoingMessagesDatabaseView:(OWSStorage *)storage; - -+ (void)asyncRegisterThreadSpecialMessagesDatabaseView:(OWSStorage *)storage; - -+ (void)asyncRegisterIncompleteViewOnceMessagesDatabaseView:(OWSStorage *)storage; - -+ (void)asyncRegisterLazyRestoreAttachmentsDatabaseView:(OWSStorage *)storage; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/TSDatabaseView.m b/SignalServiceKit/src/Storage/TSDatabaseView.m deleted file mode 100644 index f7c5b6fe95..0000000000 --- a/SignalServiceKit/src/Storage/TSDatabaseView.m +++ /dev/null @@ -1,519 +0,0 @@ -// -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. -// - -#import "TSDatabaseView.h" -#import "OWSDevice.h" -#import "OWSReadTracking.h" -#import "TSAttachment.h" -#import "TSAttachmentPointer.h" -#import "TSIncomingMessage.h" -#import "TSInvalidIdentityKeyErrorMessage.h" -#import "TSOutgoingMessage.h" -#import "TSThread.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -NSString *const TSInboxGroup = @"TSInboxGroup"; -NSString *const TSArchiveGroup = @"TSArchiveGroup"; - -NSString *const TSUnreadIncomingMessagesGroup = @"TSUnreadIncomingMessagesGroup"; -NSString *const TSSecondaryDevicesGroup = @"TSSecondaryDevicesGroup"; - -// YAPDB BUG: when changing from non-persistent to persistent view, we had to rename TSThreadDatabaseViewExtensionName -// -> TSThreadDatabaseViewExtensionName2 to work around https://github.com/yapstudios/YapDatabase/issues/324 -NSString *const TSThreadDatabaseViewExtensionName = @"TSThreadDatabaseViewExtensionName2"; - -// We sort interactions by a monotonically increasing counter. -// -// Previously we sorted the interactions database by local timestamp, which was problematic if the local clock changed. -// We need to maintain the legacy extension for purposes of migration. -// -// The "Legacy" sorting extension name constant has the same value as always, so that it won't need to be rebuilt, while -// the "Modern" sorting extension name constant has the same symbol name that we've always used for sorting -// interactions, so that the callsites won't need to change. -NSString *const TSMessageDatabaseViewExtensionName = @"TSMessageDatabaseViewExtensionName_Monotonic"; -NSString *const TSMessageDatabaseViewExtensionName_Legacy = @"TSMessageDatabaseViewExtensionName"; - -NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName = @"TSThreadOutgoingMessageDatabaseViewExtensionName"; -NSString *const TSThreadSpecialMessagesDatabaseViewExtensionName = @"TSThreadSpecialMessagesDatabaseViewExtensionName"; -NSString *const TSIncompleteViewOnceMessagesDatabaseViewExtensionName - = @"TSIncompleteViewOnceMessagesDatabaseViewExtensionName"; -NSString *const TSIncompleteViewOnceMessagesGroup = @"TSIncompleteViewOnceMessagesGroup"; -NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName - = @"TSLazyRestoreAttachmentsDatabaseViewExtensionName"; -NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"; -NSString *const TSInteractionsBySortIdDatabaseViewExtensionName = @"TSInteractionsBySortIdDatabaseViewExtensionName"; -NSString *const TSInteractionsBySortIdGroup = @"TSInteractionsBySortIdGroup"; - -@interface OWSStorage (TSDatabaseView) - -- (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName; - -@end - -#pragma mark - - -@implementation TSDatabaseView - -+ (void)registerCrossProcessNotifier:(OWSStorage *)storage -{ - OWSAssertDebug(storage); - - // I don't think the identifier and name of this extension matter for our purposes, - // so long as they don't conflict with any other extension names. - YapDatabaseExtension *extension = - [[YapDatabaseCrossProcessNotification alloc] initWithIdentifier:@"SignalCrossProcessNotifier"]; - [storage registerExtension:extension withName:@"SignalCrossProcessNotifier"]; -} - -+ (void)registerMessageDatabaseViewWithName:(NSString *)viewName - viewGrouping:(YapDatabaseViewGrouping *)viewGrouping - version:(NSString *)version - storage:(OWSStorage *)storage -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(viewName.length > 0); - OWSAssertDebug((viewGrouping)); - OWSAssertDebug(storage); - - YapDatabaseView *existingView = [storage registeredExtension:viewName]; - if (existingView) { - OWSFailDebug(@"Registered database view twice: %@", viewName); - return; - } - - YapDatabaseViewSorting *viewSorting = [self messagesSorting]; - - YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init]; - options.isPersistent = YES; - options.allowedCollections = - [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSInteraction collection]]]; - - YapDatabaseView *view = [[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping - sorting:viewSorting - versionTag:version - options:options]; - [storage asyncRegisterExtension:view withName:viewName]; -} - -+ (void)asyncRegisterThreadSpecialMessagesDatabaseView:(OWSStorage *)storage -{ - YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( - YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { - if (![object isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object class], collection); - return nil; - } - TSInteraction *interaction = (TSInteraction *)object; - if (interaction.isSpecialMessage) { - return interaction.uniqueThreadId; - } - return nil; - }]; - - [self registerMessageDatabaseViewWithName:TSThreadSpecialMessagesDatabaseViewExtensionName - viewGrouping:viewGrouping - version:@"2" - storage:storage]; -} - -+ (void)asyncRegisterIncompleteViewOnceMessagesDatabaseView:(OWSStorage *)storage -{ - YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( - YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { - if (![object isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object class], collection); - return nil; - } - if (![object isKindOfClass:[TSMessage class]]) { - return nil; - } - TSMessage *message = (TSMessage *)object; - if (message.isViewOnceMessage && !message.isViewOnceComplete) { - return TSIncompleteViewOnceMessagesGroup; - } else { - return nil; - } - }]; - - [self registerMessageDatabaseViewWithName:TSIncompleteViewOnceMessagesDatabaseViewExtensionName - viewGrouping:viewGrouping - version:@"1" - storage:storage]; -} - -+ (void)asyncRegisterLegacyThreadInteractionsDatabaseView:(OWSStorage *)storage -{ - OWSAssertIsOnMainThread(); - OWSAssert(storage); - - YapDatabaseView *existingView = [storage registeredExtension:TSMessageDatabaseViewExtensionName_Legacy]; - if (existingView) { - OWSFailDebug(@"Registered database view twice: %@", TSMessageDatabaseViewExtensionName_Legacy); - return; - } - - YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( - YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { - if (![object isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"%@ Unexpected entity %@ in collection: %@", self.logTag, [object class], collection); - return nil; - } - TSInteraction *interaction = (TSInteraction *)object; - - return interaction.uniqueThreadId; - }]; - - YapDatabaseViewSorting *viewSorting = - [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction, - NSString *group, - NSString *collection1, - NSString *key1, - id object1, - NSString *collection2, - NSString *key2, - id object2) { - if (![object1 isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"%@ Unexpected entity %@ in collection: %@", self.logTag, [object1 class], collection1); - return NSOrderedSame; - } - if (![object2 isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"%@ Unexpected entity %@ in collection: %@", self.logTag, [object2 class], collection2); - return NSOrderedSame; - } - TSInteraction *interaction1 = (TSInteraction *)object1; - TSInteraction *interaction2 = (TSInteraction *)object2; - - // Legit usage of timestampForLegacySorting since we're registering the - // legacy extension - uint64_t timestamp1 = interaction1.timestampForLegacySorting; - uint64_t timestamp2 = interaction2.timestampForLegacySorting; - - if (timestamp1 > timestamp2) { - return NSOrderedDescending; - } else if (timestamp1 < timestamp2) { - return NSOrderedAscending; - } else { - return NSOrderedSame; - } - }]; - - YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; - options.isPersistent = YES; - options.allowedCollections = - [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSInteraction collection]]]; - - YapDatabaseView *view = - [[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"1" options:options]; - - [storage asyncRegisterExtension:view withName:TSMessageDatabaseViewExtensionName_Legacy]; -} - -+ (void)asyncRegisterInteractionsBySortIdDatabaseView:(OWSStorage *)storage -{ - OWSAssertIsOnMainThread(); - OWSAssert(storage); - - YapDatabaseView *existingView = [storage registeredExtension:TSInteractionsBySortIdDatabaseViewExtensionName]; - if (existingView) { - OWSFailDebug(@"Registered database view twice: %@", TSInteractionsBySortIdDatabaseViewExtensionName); - return; - } - - YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( - YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { - if (![object isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"%@ Unexpected entity %@ in collection: %@", self.logTag, [object class], collection); - return nil; - } - return TSInteractionsBySortIdGroup; - }]; - - YapDatabaseViewSorting *viewSorting = - [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction, - NSString *group, - NSString *collection1, - NSString *key1, - id object1, - NSString *collection2, - NSString *key2, - id object2) { - if (![object1 isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"%@ Unexpected entity %@ in collection: %@", self.logTag, [object1 class], collection1); - return NSOrderedSame; - } - if (![object2 isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"%@ Unexpected entity %@ in collection: %@", self.logTag, [object2 class], collection2); - return NSOrderedSame; - } - TSInteraction *interaction1 = (TSInteraction *)object1; - TSInteraction *interaction2 = (TSInteraction *)object2; - - uint64_t sortId1 = interaction1.sortId; - uint64_t sortId2 = interaction2.sortId; - uint64_t timestamp1 = interaction1.timestampForLegacySorting; - uint64_t timestamp2 = interaction2.timestampForLegacySorting; - - if (sortId1 > sortId2) { - return NSOrderedDescending; - } else if (sortId1 < sortId2) { - return NSOrderedAscending; - } else { - // If sort ids are equal, use timestamp to restore correct ordering. - if (timestamp1 > timestamp2) { - return NSOrderedDescending; - } else if (timestamp1 < timestamp2) { - return NSOrderedAscending; - } else { - // Ensure sort is stable if sort ids are equal. - return [interaction1.uniqueId compare:interaction2.uniqueId]; - } - } - }]; - - YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; - options.isPersistent = YES; - options.allowedCollections = - [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSInteraction collection]]]; - - YapDatabaseView *view = - [[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"1" options:options]; - - [storage asyncRegisterExtension:view withName:TSInteractionsBySortIdDatabaseViewExtensionName]; -} - -+ (void)asyncRegisterThreadInteractionsDatabaseView:(OWSStorage *)storage -{ - YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( - YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { - if (![object isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object class], collection); - return nil; - } - TSInteraction *interaction = (TSInteraction *)object; - - return interaction.uniqueThreadId; - }]; - - [self registerMessageDatabaseViewWithName:TSMessageDatabaseViewExtensionName - viewGrouping:viewGrouping - version:@"2" - storage:storage]; -} - -+ (void)asyncRegisterThreadOutgoingMessagesDatabaseView:(OWSStorage *)storage -{ - YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( - YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { - if ([object isKindOfClass:[TSOutgoingMessage class]]) { - return ((TSOutgoingMessage *)object).uniqueThreadId; - } - return nil; - }]; - - [self registerMessageDatabaseViewWithName:TSThreadOutgoingMessageDatabaseViewExtensionName - viewGrouping:viewGrouping - version:@"3" - storage:storage]; -} - -+ (void)asyncRegisterThreadDatabaseView:(OWSStorage *)storage -{ - YapDatabaseView *threadView = [storage registeredExtension:TSThreadDatabaseViewExtensionName]; - if (threadView) { - OWSFailDebug(@"Registered database view twice: %@", TSThreadDatabaseViewExtensionName); - return; - } - - YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( - YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { - if (![object isKindOfClass:[TSThread class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object class], collection); - return nil; - } - TSThread *thread = (TSThread *)object; - - if (thread.shouldThreadBeVisible) { - // Do nothing; we never hide threads that have ever had a message. - } else { - YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSMessageDatabaseViewExtensionName]; - OWSAssertDebug(viewTransaction); - NSUInteger threadMessageCount = [viewTransaction numberOfItemsInGroup:thread.uniqueId]; - if (threadMessageCount < 1) { - OWSAssertDebug(!thread.shouldThreadBeVisible); - return nil; - } - } - - return thread.isArchived ? TSArchiveGroup : TSInboxGroup; - }]; - - YapDatabaseViewSorting *viewSorting = [self threadSorting]; - - YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init]; - options.isPersistent = YES; - options.allowedCollections = - [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSThread collection]]]; - - YapDatabaseView *databaseView = - [[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"4" options:options]; - - [storage asyncRegisterExtension:databaseView withName:TSThreadDatabaseViewExtensionName]; -} - -+ (YapDatabaseViewSorting *)threadSorting { - return [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction, - NSString *group, - NSString *collection1, - NSString *key1, - id object1, - NSString *collection2, - NSString *key2, - id object2) { - if (![object1 isKindOfClass:[TSThread class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object1 class], collection1); - return NSOrderedSame; - } - if (![object2 isKindOfClass:[TSThread class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object2 class], collection2); - return NSOrderedSame; - } - TSThread *thread1 = (TSThread *)object1; - TSThread *thread2 = (TSThread *)object2; - if ([group isEqualToString:TSArchiveGroup] || [group isEqualToString:TSInboxGroup]) { - - NSDate *longAgo = [NSDate dateWithTimeIntervalSince1970:0]; - - TSInteraction *_Nullable lastInteractionForInbox1 = - [thread1 lastInteractionForInboxWithTransaction:transaction.asAnyRead]; - NSDate *date1 = lastInteractionForInbox1 ? lastInteractionForInbox1.receivedAtDate : thread1.creationDate; - if (date1 == nil) { - date1 = longAgo; - } - - TSInteraction *_Nullable lastInteractionForInbox2 = - [thread2 lastInteractionForInboxWithTransaction:transaction.asAnyRead]; - NSDate *date2 = lastInteractionForInbox2 ? lastInteractionForInbox2.receivedAtDate : thread2.creationDate; - if (date2 == nil) { - date2 = longAgo; - } - - return [date1 compare:date2]; - } - - return NSOrderedSame; - }]; -} - -+ (YapDatabaseViewSorting *)messagesSorting { - return [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction, - NSString *group, - NSString *collection1, - NSString *key1, - id object1, - NSString *collection2, - NSString *key2, - id object2) { - if (![object1 isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object1 class], collection1); - return NSOrderedSame; - } - if (![object2 isKindOfClass:[TSInteraction class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object2 class], collection2); - return NSOrderedSame; - } - TSInteraction *message1 = (TSInteraction *)object1; - TSInteraction *message2 = (TSInteraction *)object2; - - return [message1 compareForSorting:message2]; - }]; -} - -+ (void)asyncRegisterLazyRestoreAttachmentsDatabaseView:(OWSStorage *)storage -{ - YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable( - YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { - if (![object isKindOfClass:[TSAttachment class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object class], collection); - return nil; - } - if (![object isKindOfClass:[TSAttachmentPointer class]]) { - return nil; - } - TSAttachmentPointer *attachmentPointer = (TSAttachmentPointer *)object; - if ([attachmentPointer lazyRestoreFragmentWithTransaction:transaction.asAnyRead]) { - return TSLazyRestoreAttachmentsGroup; - } else { - return nil; - } - }]; - - YapDatabaseViewSorting *viewSorting = - [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction, - NSString *group, - NSString *collection1, - NSString *key1, - id object1, - NSString *collection2, - NSString *key2, - id object2) { - if (![object1 isKindOfClass:[TSAttachmentPointer class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object1 class], collection1); - return NSOrderedSame; - } - if (![object2 isKindOfClass:[TSAttachmentPointer class]]) { - OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object2 class], collection2); - return NSOrderedSame; - } - - // Specific ordering doesn't matter; we just need a stable ordering. - TSAttachmentPointer *attachmentPointer1 = (TSAttachmentPointer *)object1; - TSAttachmentPointer *attachmentPointer2 = (TSAttachmentPointer *)object2; - return [attachmentPointer1.uniqueId compare:attachmentPointer2.uniqueId]; - }]; - - YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; - options.isPersistent = YES; - options.allowedCollections = - [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSAttachment collection]]]; - YapDatabaseView *view = - [[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"4" options:options]; - [storage asyncRegisterExtension:view withName:TSLazyRestoreAttachmentsDatabaseViewExtensionName]; -} - -// MJK TODO - dynamic interactions -+ (id)threadOutgoingMessageDatabaseView:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - - id result = [transaction ext:TSThreadOutgoingMessageDatabaseViewExtensionName]; - OWSAssertDebug(result); - return result; -} - -+ (id)threadSpecialMessagesDatabaseView:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - - id result = [transaction ext:TSThreadSpecialMessagesDatabaseViewExtensionName]; - OWSAssertDebug(result); - return result; -} - -+ (id)incompleteViewOnceMessagesDatabaseView:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertDebug(transaction); - - id result = [transaction ext:TSIncompleteViewOnceMessagesDatabaseViewExtensionName]; - OWSAssertDebug(result); - return result; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/TSYapDatabaseObject.h b/SignalServiceKit/src/Storage/TSYapDatabaseObject.h index f39d61ac33..60323501d0 100644 --- a/SignalServiceKit/src/Storage/TSYapDatabaseObject.h +++ b/SignalServiceKit/src/Storage/TSYapDatabaseObject.h @@ -8,8 +8,6 @@ NS_ASSUME_NONNULL_BEGIN @class SDSAnyWriteTransaction; @class SDSDatabaseStorage; -@class YapDatabaseReadTransaction; -@class YapDatabaseReadWriteTransaction; @protocol SDSRecordDelegate @@ -19,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - - +// TODO: Rename and/or merge with BaseModel. @interface TSYapDatabaseObject : MTLModel /** @@ -75,20 +73,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)anyWillRemoveWithTransaction:(SDSAnyWriteTransaction *)transaction; - (void)anyDidRemoveWithTransaction:(SDSAnyWriteTransaction *)transaction; -#pragma mark - YDB Deprecation - -// These ydb_ methods should only be used before -// and during the ydb-to-grdb migration. -+ (void)ydb_enumerateCollectionObjectsWithTransaction:(YapDatabaseReadTransaction *)transaction - usingBlock:(void (^)(id object, BOOL *stop))block; -+ (nullable instancetype)ydb_fetchObjectWithUniqueID:(NSString *)uniqueID - transaction:(YapDatabaseReadTransaction *)transaction - NS_SWIFT_NAME(ydb_fetch(uniqueId:transaction:)); -- (void)ydb_reloadWithTransaction:(YapDatabaseReadTransaction *)transaction; -- (void)ydb_reloadWithTransaction:(YapDatabaseReadTransaction *)transaction ignoreMissing:(BOOL)ignoreMissing; -- (void)ydb_saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; -- (void)ydb_removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/TSYapDatabaseObject.m b/SignalServiceKit/src/Storage/TSYapDatabaseObject.m index be907999b0..0aae5393a2 100644 --- a/SignalServiceKit/src/Storage/TSYapDatabaseObject.m +++ b/SignalServiceKit/src/Storage/TSYapDatabaseObject.m @@ -8,52 +8,6 @@ NS_ASSUME_NONNULL_BEGIN -// This macro is only intended to be used within TSYapDatabaseObject. -#define OWSAssertCanReadYDB() \ - do { \ - if (!self.databaseStorage.canReadFromYdb) { \ - OWSLogError(@"storageMode: %@.", SSKFeatureFlags.storageModeDescription); \ - OWSLogError( \ - @"StorageCoordinatorState: %@.", NSStringFromStorageCoordinatorState(self.storageCoordinator.state)); \ - OWSLogError(@"dataStoreForUI: %@.", NSStringForDataStore(StorageCoordinator.dataStoreForUI)); \ - switch (SSKFeatureFlags.storageModeStrictness) { \ - case StorageModeStrictnessFail: \ - OWSFail(@"Unexpected YDB read."); \ - break; \ - case StorageModeStrictnessFailDebug: \ - OWSFailDebug(@"Unexpected YDB read."); \ - break; \ - case StorageModeStrictnessLog: \ - OWSLogError(@"Unexpected YDB read."); \ - break; \ - } \ - } \ - } while (NO) - -// This macro is only intended to be used within TSYapDatabaseObject. -#define OWSAssertCanWriteYDB() \ - do { \ - if (!self.databaseStorage.canWriteToYdb) { \ - OWSLogError(@"storageMode: %@.", SSKFeatureFlags.storageModeDescription); \ - OWSLogError( \ - @"StorageCoordinatorState: %@.", NSStringFromStorageCoordinatorState(self.storageCoordinator.state)); \ - OWSLogError(@"dataStoreForUI: %@.", NSStringForDataStore(StorageCoordinator.dataStoreForUI)); \ - switch (SSKFeatureFlags.storageModeStrictness) { \ - case StorageModeStrictnessFail: \ - OWSFail(@"Unexpected YDB write."); \ - break; \ - case StorageModeStrictnessFailDebug: \ - OWSFailDebug(@"Unexpected YDB write."); \ - break; \ - case StorageModeStrictnessLog: \ - OWSLogError(@"Unexpected YDB write."); \ - break; \ - } \ - } \ - } while (NO) - -#pragma mark - - @interface TSYapDatabaseObject () @property (atomic, nullable) NSNumber *grdbId; @@ -127,74 +81,6 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - -- (void)ydb_saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertCanWriteYDB(); - - if (!self.shouldBeSaved) { - OWSLogDebug(@"Skipping save for %@.", [self class]); - - return; - } - - [transaction setObject:self forKey:self.uniqueId inCollection:[[self class] collection]]; -} - -- (void)ydb_removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertCanWriteYDB(); - - [transaction removeObjectForKey:self.uniqueId inCollection:[[self class] collection]]; -} - -+ (void)ydb_enumerateCollectionObjectsWithTransaction:(YapDatabaseReadTransaction *)transaction - usingBlock:(void (^)(id object, BOOL *stop))block -{ - OWSAssertCanReadYDB(); - - // Ignoring most of the YapDB parameters, and just passing through the ones we usually use. - void (^yapBlock)(NSString *key, id object, id metadata, BOOL *stop) - = ^void(NSString *key, id object, id metadata, BOOL *stop) { - block(object, stop); - }; - - [transaction enumerateRowsInCollection:[self collection] usingBlock:yapBlock]; -} - -+ (nullable instancetype)ydb_fetchObjectWithUniqueID:(NSString *)uniqueID - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertCanReadYDB(); - - return [transaction objectForKey:uniqueID inCollection:[self collection]]; -} - -#pragma mark Reload - -- (void)ydb_reloadWithTransaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssertCanReadYDB(); - - [self ydb_reloadWithTransaction:transaction ignoreMissing:NO]; -} - -- (void)ydb_reloadWithTransaction:(YapDatabaseReadTransaction *)transaction ignoreMissing:(BOOL)ignoreMissing -{ - OWSAssertCanReadYDB(); - - TSYapDatabaseObject *latest = [[self class] ydb_fetchObjectWithUniqueID:self.uniqueId transaction:transaction]; - if (!latest) { - if (!ignoreMissing) { - OWSFailDebug(@"`latest` was unexpectedly nil"); - } - return; - } - - [self setValuesForKeysWithDictionary:latest.dictionaryValue]; -} - -#pragma mark - - - (BOOL)shouldBeSaved { return YES; diff --git a/SignalServiceKit/src/Storage/YAPDBMediaGalleryManager.h b/SignalServiceKit/src/Storage/YAPDBMediaGalleryManager.h deleted file mode 100644 index 59aeda25b1..0000000000 --- a/SignalServiceKit/src/Storage/YAPDBMediaGalleryManager.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class OWSStorage; - -@interface YAPDBMediaGalleryManager : NSObject - -+ (NSString *)databaseExtensionName; -+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/YAPDBMediaGalleryManager.m b/SignalServiceKit/src/Storage/YAPDBMediaGalleryManager.m deleted file mode 100644 index 150f11d6be..0000000000 --- a/SignalServiceKit/src/Storage/YAPDBMediaGalleryManager.m +++ /dev/null @@ -1,126 +0,0 @@ -// -// Copyright (c) 2021 Open Whisper Systems. All rights reserved. -// - -#import "YAPDBMediaGalleryManager.h" -#import "OWSStorage.h" -#import "TSAttachmentStream.h" -#import "TSMessage.h" -#import "TSThread.h" -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -// The value retains the class's old name. -static NSString *const YAPDBMediaGalleryManagerExtensionName = @"YAPDBMediaGalleryFinderExtensionName"; - -@implementation YAPDBMediaGalleryManager - -+ (NSString *)mediaGroupWithThreadId:(NSString *)threadId -{ - return [NSString stringWithFormat:@"%@-media", threadId]; -} - -#pragma mark - Extension registration - -+ (NSString *)databaseExtensionName -{ - return YAPDBMediaGalleryManagerExtensionName; -} - -+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage -{ - [storage asyncRegisterExtension:[self mediaGalleryDatabaseExtension] - withName:YAPDBMediaGalleryManagerExtensionName]; -} - -+ (YapDatabaseAutoView *)mediaGalleryDatabaseExtension -{ - YapDatabaseViewSorting *sorting = - [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *_Nonnull transaction, - NSString *_Nonnull group, - NSString *_Nonnull collection1, - NSString *_Nonnull key1, - id _Nonnull object1, - NSString *_Nonnull collection2, - NSString *_Nonnull key2, - id _Nonnull object2) { - if (![object1 isKindOfClass:[TSAttachment class]]) { - OWSFailDebug(@"Unexpected object while sorting: %@", [object1 class]); - return NSOrderedSame; - } - TSAttachment *attachment1 = (TSAttachment *)object1; - - if (![object2 isKindOfClass:[TSAttachment class]]) { - OWSFailDebug(@"Unexpected object while sorting: %@", [object2 class]); - return NSOrderedSame; - } - TSAttachment *attachment2 = (TSAttachment *)object2; - - TSMessage *_Nullable message1 = [attachment1 fetchAlbumMessageWithTransaction:transaction.asAnyRead]; - TSMessage *_Nullable message2 = [attachment2 fetchAlbumMessageWithTransaction:transaction.asAnyRead]; - if (message1 == nil || message2 == nil) { - OWSFailDebug(@"couldn't find albumMessage"); - return NSOrderedSame; - } - - if ([message1.uniqueId isEqualToString:message2.uniqueId]) { - NSUInteger index1 = [message1.attachmentIds indexOfObject:attachment1.uniqueId]; - NSUInteger index2 = [message1.attachmentIds indexOfObject:attachment2.uniqueId]; - - if (index1 == NSNotFound || index2 == NSNotFound) { - OWSFailDebug(@"couldn't find attachmentId in it's albumMessage"); - return NSOrderedSame; - } - return [@(index1) compare:@(index2)]; - } else { - return [message1 compareForSorting:message2]; - } - }]; - - YapDatabaseViewGrouping *grouping = - [YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable(YapDatabaseReadTransaction *_Nonnull transaction, - NSString *_Nonnull collection, - NSString *_Nonnull key, - id _Nonnull object) { - // Don't include nil or not yet downloaded attachments. - if (![object isKindOfClass:[TSAttachmentStream class]]) { - return nil; - } - - TSAttachmentStream *attachment = (TSAttachmentStream *)object; - if (attachment.albumMessageId == nil) { - return nil; - } - - if (!attachment.isValidVisualMedia) { - return nil; - } - - TSMessage *message = [attachment fetchAlbumMessageWithTransaction:transaction.asAnyRead]; - if (message == nil) { - OWSFailDebug(@"message was unexpectedly nil"); - return nil; - } - if (message.isViewOnceMessage) { - // Don't show attachments from "view-once messages" in media gallery. - return nil; - } - - return [self mediaGroupWithThreadId:message.uniqueThreadId]; - }]; - - YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; - options.allowedCollections = - [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:TSAttachment.collection]]; - - return [[YapDatabaseAutoView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"4" options:options]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/YDBStorage.h b/SignalServiceKit/src/Storage/YDBStorage.h new file mode 100644 index 0000000000..719a2f92c2 --- /dev/null +++ b/SignalServiceKit/src/Storage/YDBStorage.h @@ -0,0 +1,18 @@ +// +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. +// + +NS_ASSUME_NONNULL_BEGIN + +@interface YDBStorage : NSObject + ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; + ++ (void)deleteYDBStorage NS_SWIFT_NAME(deleteYDBStorage()); + ++ (BOOL)hasAnyYdbFile; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/YDBStorage.m b/SignalServiceKit/src/Storage/YDBStorage.m new file mode 100644 index 0000000000..bc73861416 --- /dev/null +++ b/SignalServiceKit/src/Storage/YDBStorage.m @@ -0,0 +1,127 @@ +// +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. +// + +#import "YDBStorage.h" +#import "OWSFileSystem.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +static NSString *keychainService = @"TSKeyChainService"; +static NSString *keychainDBLegacyPassphrase = @"TSDatabasePass"; +static NSString *keychainDBCipherKeySpec = @"OWSDatabaseCipherKeySpec"; + +#pragma mark - + +@implementation YDBStorage + ++ (NSString *)legacyDatabaseDirPath +{ + return [OWSFileSystem appDocumentDirectoryPath]; +} + ++ (NSString *)sharedDataDatabaseDirPath +{ + return [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"database"]; +} + ++ (NSString *)databaseFilename +{ + return @"Signal.sqlite"; +} + ++ (NSString *)databaseFilename_SHM +{ + return [self.databaseFilename stringByAppendingString:@"-shm"]; +} + ++ (NSString *)databaseFilename_WAL +{ + return [self.databaseFilename stringByAppendingString:@"-wal"]; +} + ++ (NSString *)legacyDatabaseFilePath +{ + return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename]; +} + ++ (NSString *)legacyDatabaseFilePath_SHM +{ + return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_SHM]; +} + ++ (NSString *)legacyDatabaseFilePath_WAL +{ + return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL]; +} + ++ (NSString *)sharedDataDatabaseFilePath +{ + return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename]; +} + ++ (NSString *)sharedDataDatabaseFilePath_SHM +{ + return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_SHM]; +} + ++ (NSString *)sharedDataDatabaseFilePath_WAL +{ + return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL]; +} + +#pragma mark - + ++ (void)deleteYDBStorage +{ + [self deleteDatabaseFiles]; + [self deleteDBKeys]; +} + ++ (void)deleteDatabaseFiles +{ + [OWSFileSystem deleteFileIfExists:self.legacyDatabaseFilePath]; + [OWSFileSystem deleteFileIfExists:self.legacyDatabaseFilePath_SHM]; + [OWSFileSystem deleteFileIfExists:self.legacyDatabaseFilePath_WAL]; + [OWSFileSystem deleteFileIfExists:self.sharedDataDatabaseFilePath]; + [OWSFileSystem deleteFileIfExists:self.sharedDataDatabaseFilePath_SHM]; + [OWSFileSystem deleteFileIfExists:self.sharedDataDatabaseFilePath_WAL]; + // NOTE: It's NOT safe to delete OWSPrimaryStorage.legacyDatabaseDirPath + // which is the app document dir. + [OWSFileSystem deleteContentsOfDirectory:self.sharedDataDatabaseDirPath]; +} + ++ (BOOL)hasAnyYdbFile +{ + return ([OWSFileSystem fileOrFolderExistsAtPath:self.legacyDatabaseFilePath] || + [OWSFileSystem fileOrFolderExistsAtPath:self.legacyDatabaseFilePath_SHM] || + [OWSFileSystem fileOrFolderExistsAtPath:self.legacyDatabaseFilePath_WAL] || + [OWSFileSystem fileOrFolderExistsAtPath:self.sharedDataDatabaseFilePath] || + [OWSFileSystem fileOrFolderExistsAtPath:self.sharedDataDatabaseFilePath_SHM] || + [OWSFileSystem fileOrFolderExistsAtPath:self.sharedDataDatabaseFilePath_WAL]); +} + +#pragma mark - Keychain + ++ (void)deleteDBKeys +{ + NSError *_Nullable error; + BOOL result = [CurrentAppContext().keychainStorage removeWithService:keychainService + key:keychainDBLegacyPassphrase + error:&error]; + if (error || !result) { + OWSFailDebug(@"could not remove legacy passphrase."); + } + result = [CurrentAppContext().keychainStorage removeWithService:keychainService + key:keychainDBCipherKeySpec + error:&error]; + if (error || !result) { + OWSFailDebug(@"could not remove cipher key spec."); + } +} + + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/YapDatabaseTransaction+OWS.h b/SignalServiceKit/src/Storage/YapDatabaseTransaction+OWS.h deleted file mode 100644 index 41e417ce2a..0000000000 --- a/SignalServiceKit/src/Storage/YapDatabaseTransaction+OWS.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import -#import - -@class YapDatabaseAutoViewTransaction; -@class YapDatabaseFullTextSearchTransaction; -@class YapDatabaseSecondaryIndexTransaction; -@class YapDatabaseViewTransaction; - -NS_ASSUME_NONNULL_BEGIN - -@interface YapDatabaseReadTransaction (OWS) - -#pragma mark - Extensions - -- (nullable YapDatabaseViewTransaction *)safeViewTransaction:(NSString *)extensionName - NS_SWIFT_NAME(safeViewTransaction(_:)); -- (nullable YapDatabaseAutoViewTransaction *)safeAutoViewTransaction:(NSString *)extensionName - NS_SWIFT_NAME(safeAutoViewTransaction(_:)); -- (nullable YapDatabaseSecondaryIndexTransaction *)safeSecondaryIndexTransaction:(NSString *)extensionName - NS_SWIFT_NAME(safeSecondaryIndexTransaction(_:)); -- (nullable YapDatabaseFullTextSearchTransaction *)safeFullTextSearchTransaction:(NSString *)extensionName - NS_SWIFT_NAME(safeFullTextSearchTransaction(_:)); - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/YapDatabaseTransaction+OWS.m b/SignalServiceKit/src/Storage/YapDatabaseTransaction+OWS.m deleted file mode 100644 index 430abf6ee3..0000000000 --- a/SignalServiceKit/src/Storage/YapDatabaseTransaction+OWS.m +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "YapDatabaseTransaction+OWS.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation YapDatabaseReadTransaction (OWS) - -#pragma mark - Extensions - -- (nullable id)safe_extension:(NSString *)extensionName clazz:(Class)clazz -{ - id _Nullable result = [self extension:extensionName]; - - if (![result isKindOfClass:clazz]) { - [OWSPrimaryStorage incrementVersionOfDatabaseExtension:extensionName]; - - if (SSKFeatureFlags.strictYDBExtensions) { - OWSFail(@"Couldn't load database extension: %@.", extensionName); - } else { - LogStackTrace(); - OWSFailDebug(@"Couldn't load database extension: %@.", extensionName); - } - return nil; - } - return result; -} - -- (nullable YapDatabaseViewTransaction *)safeViewTransaction:(NSString *)extensionName -{ - return [self safe_extension:extensionName clazz:[YapDatabaseViewTransaction class]]; -} - -- (nullable YapDatabaseAutoViewTransaction *)safeAutoViewTransaction:(NSString *)extensionName -{ - return [self safe_extension:extensionName clazz:[YapDatabaseAutoViewTransaction class]]; -} - -- (nullable YapDatabaseSecondaryIndexTransaction *)safeSecondaryIndexTransaction:(NSString *)extensionName -{ - return [self safe_extension:extensionName clazz:[YapDatabaseSecondaryIndexTransaction class]]; -} - -- (nullable YapDatabaseFullTextSearchTransaction *)safeFullTextSearchTransaction:(NSString *)extensionName -{ - return [self safe_extension:extensionName clazz:[YapDatabaseFullTextSearchTransaction class]]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/TestUtils/MockSSKEnvironment.h b/SignalServiceKit/src/TestUtils/MockSSKEnvironment.h index 4633d4f7b0..0a9c1cd8ea 100644 --- a/SignalServiceKit/src/TestUtils/MockSSKEnvironment.h +++ b/SignalServiceKit/src/TestUtils/MockSSKEnvironment.h @@ -15,7 +15,6 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) id contactsManagerRef; @property (nonatomic) MessageSender *messageSenderRef; @property (nonatomic) id profileManagerRef; -@property (nonatomic, nullable) OWSPrimaryStorage *primaryStorageRef; @property (nonatomic) TSNetworkManager *networkManagerRef; @property (nonatomic) OWSMessageManager *messageManagerRef; @property (nonatomic) OWSBlockingManager *blockingManagerRef; diff --git a/SignalServiceKit/src/TestUtils/MockSSKEnvironment.m b/SignalServiceKit/src/TestUtils/MockSSKEnvironment.m index c6b8d76bfb..d9f3a40dee 100644 --- a/SignalServiceKit/src/TestUtils/MockSSKEnvironment.m +++ b/SignalServiceKit/src/TestUtils/MockSSKEnvironment.m @@ -13,7 +13,6 @@ #import "OWSIdentityManager.h" #import "OWSMessageManager.h" #import "OWSOutgoingReceiptManager.h" -#import "OWSPrimaryStorage.h" #import "OWSReadReceiptManager.h" #import "SSKPreKeyStore.h" #import "SSKSignedPreKeyStore.h" @@ -29,15 +28,6 @@ NS_ASSUME_NONNULL_BEGIN #ifdef TESTABLE_BUILD -@interface OWSPrimaryStorage (Tests) - -@property (atomic) BOOL areAsyncRegistrationsComplete; -@property (atomic) BOOL areSyncRegistrationsComplete; - -@end - -#pragma mark - - @implementation MockSSKEnvironment + (void)activate @@ -56,8 +46,6 @@ NS_ASSUME_NONNULL_BEGIN StorageCoordinator *storageCoordinator = [StorageCoordinator new]; SDSDatabaseStorage *databaseStorage = storageCoordinator.databaseStorage; - // Unlike AppSetup, we always load YDB in the tests. - OWSPrimaryStorage *primaryStorage = databaseStorage.yapPrimaryStorage; id contactsManager = [OWSFakeContactsManager new]; OWSLinkPreviewManager *linkPreviewManager = [OWSLinkPreviewManager new]; @@ -108,7 +96,6 @@ NS_ASSUME_NONNULL_BEGIN messageSenderJobQueue:messageSenderJobQueue pendingReadReceiptRecorder:[NoopPendingReadReceiptRecorder new] profileManager:[OWSFakeProfileManager new] - primaryStorage:primaryStorage networkManager:networkManager messageManager:messageManager blockingManager:blockingManager @@ -162,17 +149,11 @@ NS_ASSUME_NONNULL_BEGIN - (void)configure { __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - [self configureYdb] - .then(^{ - OWSAssertIsOnMainThread(); + [self configureGrdb].then(^{ + OWSAssertIsOnMainThread(); - return [self configureGrdb]; - }) - .then(^{ - OWSAssertIsOnMainThread(); - - dispatch_semaphore_signal(semaphore); - }); + dispatch_semaphore_signal(semaphore); + }); // Registering extensions is a complicated process than can move // on and off the main thread. While we wait for it to complete, @@ -191,22 +172,6 @@ NS_ASSUME_NONNULL_BEGIN } } -- (AnyPromise *)configureYdb -{ - if (!self.databaseStorage.canLoadYdb) { - return [AnyPromise promiseWithValue:@(1)]; - } - AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - [OWSStorage registerExtensionsWithCompletionBlock:^() { - [self.storageCoordinator markStorageSetupAsComplete]; - - // The value doesn't matter, we just need any non-NSError value. - resolve(@(1)); - }]; - }]; - return promise; -} - - (AnyPromise *)configureGrdb { OWSAssertIsOnMainThread(); diff --git a/SignalServiceKit/src/Util/Dependencies+SSK.swift b/SignalServiceKit/src/Util/Dependencies+SSK.swift index 9e716e1923..4059e7cdce 100644 --- a/SignalServiceKit/src/Util/Dependencies+SSK.swift +++ b/SignalServiceKit/src/Util/Dependencies+SSK.swift @@ -152,14 +152,6 @@ public extension NSObject { .shared } - final var primaryStorage: OWSPrimaryStorage? { - SSKEnvironment.shared.primaryStorageRef - } - - static var primaryStorage: OWSPrimaryStorage? { - SSKEnvironment.shared.primaryStorageRef - } - final var profileManager: ProfileManagerProtocol { SSKEnvironment.shared.profileManagerRef } @@ -585,14 +577,6 @@ public extension Dependencies { .shared } - var primaryStorage: OWSPrimaryStorage? { - SSKEnvironment.shared.primaryStorageRef - } - - static var primaryStorage: OWSPrimaryStorage? { - SSKEnvironment.shared.primaryStorageRef - } - var profileManager: ProfileManagerProtocol { SSKEnvironment.shared.profileManagerRef } @@ -936,15 +920,6 @@ public extension Dependencies { // MARK: - -@objc -public extension OWSPrimaryStorage { - static var shared: OWSPrimaryStorage? { - SSKEnvironment.shared.primaryStorageRef - } -} - -// MARK: - - @objc public extension OWSBlockingManager { static var shared: OWSBlockingManager { diff --git a/SignalServiceKit/src/Util/ExperienceUpgrade+SDS.swift b/SignalServiceKit/src/Util/ExperienceUpgrade+SDS.swift index 86e45cfe78..f515afcc73 100644 --- a/SignalServiceKit/src/Util/ExperienceUpgrade+SDS.swift +++ b/SignalServiceKit/src/Util/ExperienceUpgrade+SDS.swift @@ -365,8 +365,6 @@ public extension ExperienceUpgrade { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ExperienceUpgrade.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(ExperienceUpgradeRecord.databaseTableName) WHERE \(experienceUpgradeColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -397,14 +395,6 @@ public extension ExperienceUpgrade { batchSize: UInt, block: @escaping (ExperienceUpgrade, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ExperienceUpgrade.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? ExperienceUpgrade else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = ExperienceUpgrade.grdbFetchCursor(transaction: grdbTransaction) @@ -446,10 +436,6 @@ public extension ExperienceUpgrade { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: ExperienceUpgrade.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -481,8 +467,6 @@ public extension ExperienceUpgrade { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: ExperienceUpgrade.collection()) case .grdbRead(let grdbTransaction): return ExperienceUpgradeRecord.ows_fetchCount(grdbTransaction.database) } @@ -492,8 +476,6 @@ public extension ExperienceUpgrade { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: ExperienceUpgrade.collection()) case .grdbWrite(let grdbTransaction): do { try ExperienceUpgradeRecord.deleteAll(grdbTransaction.database) @@ -542,8 +524,6 @@ public extension ExperienceUpgrade { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: ExperienceUpgrade.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(ExperienceUpgradeRecord.databaseTableName) WHERE \(experienceUpgradeColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Util/FeatureFlags.swift b/SignalServiceKit/src/Util/FeatureFlags.swift index b219e9eba4..2ab5b63a6b 100644 --- a/SignalServiceKit/src/Util/FeatureFlags.swift +++ b/SignalServiceKit/src/Util/FeatureFlags.swift @@ -25,30 +25,13 @@ let build: FeatureBuild = OWSIsDebugBuild() ? .dev : .qa @objc public enum StorageMode: Int { - // Only use YDB. This should be used in production until we ship - // the YDB-to-GRDB migration. - case ydbForAll - // Use GRDB, migrating if possible on every launch. - // If no YDB database exists, a throwaway db is not used. - // - // Supercedes grdbMigratesFreshDBEveryLaunch. - // - // TODO: Remove. - case grdbThrowawayIfMigrating - // Use GRDB under certain conditions. - // - // TODO: Remove. - case grdbForAlreadyMigrated - case grdbForLegacyUsersOnly - case grdbForNewUsersOnly - // Use GRDB, migrating once if necessary. + // Use GRDB. case grdbForAll // These modes can be used while running tests. // They are more permissive than the release modes. // // The build shepherd should be running the test - // suites in .ydbTests and .grdbTests modes before each release. - case ydbTests + // suites in .grdbTests mode before each release. case grdbTests } @@ -57,20 +40,8 @@ public enum StorageMode: Int { extension StorageMode: CustomStringConvertible { public var description: String { switch self { - case .ydbForAll: - return ".ydbForAll" - case .grdbThrowawayIfMigrating: - return ".grdbThrowawayIfMigrating" - case .grdbForAlreadyMigrated: - return ".grdbForAlreadyMigrated" - case .grdbForLegacyUsersOnly: - return ".grdbForLegacyUsersOnly" - case .grdbForNewUsersOnly: - return ".grdbForNewUsersOnly" case .grdbForAll: return ".grdbForAll" - case .ydbTests: - return ".ydbTests" case .grdbTests: return ".grdbTests" } @@ -79,18 +50,6 @@ extension StorageMode: CustomStringConvertible { // MARK: - -@objc -public enum StorageModeStrictness: Int { - // For DEBUG, QA and beta builds only. - case fail - // For production - case failDebug - // Temporary value to be used until existing issues are resolved. - case log -} - -// MARK: - - /// By centralizing feature flags here and documenting their rollout plan, it's easier to review /// which feature flags are in play. @objc(SSKFeatureFlags) @@ -99,20 +58,12 @@ public class FeatureFlags: BaseFlags { @objc public static var storageMode: StorageMode { if CurrentAppContext().isRunningTests { - // We should be running the tests using both .ydbTests or .grdbTests. return .grdbTests } else { return .grdbForAll } } - // Don't enable this flag in production. - // At least, not yet. - @objc - public static var storageModeStrictness: StorageModeStrictness { - return build.includes(.beta) ? .fail : .failDebug - } - @objc public static var storageModeDescription: String { return "\(storageMode)" @@ -128,10 +79,6 @@ public class FeatureFlags: BaseFlags { @objc public static let strictSyncTranscriptTimestamps = false - // Don't enable this flag in production. - @objc - public static let strictYDBExtensions = build.includes(.beta) - @objc public static let phoneNumberSharing = build.includes(.qa) diff --git a/SignalServiceKit/src/Util/JobQueue.swift b/SignalServiceKit/src/Util/JobQueue.swift index 3aef8a4b93..71f8e58926 100644 --- a/SignalServiceKit/src/Util/JobQueue.swift +++ b/SignalServiceKit/src/Util/JobQueue.swift @@ -369,7 +369,6 @@ public class JobRecordFinderObjC: NSObject { public class AnyJobRecordFinder where JobRecordType: SSKJobRecord { lazy var grdbAdapter = GRDBJobRecordFinder() - lazy var yapAdapter = YAPDBJobRecordFinder() public init() {} } @@ -379,8 +378,6 @@ extension AnyJobRecordFinder: JobRecordFinder { switch transaction.readTransaction { case .grdbRead(let grdbRead): grdbAdapter.enumerateJobRecords(label: label, transaction: grdbRead, block: block) - case .yapRead(let yapRead): - yapAdapter.enumerateJobRecords(label: label, transaction: yapRead, block: block) } } @@ -388,8 +385,6 @@ extension AnyJobRecordFinder: JobRecordFinder { switch transaction.readTransaction { case .grdbRead(let grdbRead): grdbAdapter.enumerateJobRecords(label: label, status: status, transaction: grdbRead, block: block) - case .yapRead(let yapRead): - yapAdapter.enumerateJobRecords(label: label, status: status, transaction: yapRead, block: block) } } } @@ -450,88 +445,3 @@ extension GRDBJobRecordFinder: JobRecordFinder { } } } - -@objc -public class YAPDBJobRecordFinderSetup: NSObject { - @objc - public class func asyncRegisterDatabaseExtensionObjC(storage: OWSStorage) { - YAPDBJobRecordFinder.asyncRegisterDatabaseExtension(storage: storage) - } -} - -public class YAPDBJobRecordFinder where JobRecordType: SSKJobRecord { - public static var dbExtensionName: String { - return "SecondaryIndexJobRecord" - } - - func ext(transaction: YapDatabaseReadTransaction) -> YapDatabaseSecondaryIndexTransaction? { - return transaction.safeSecondaryIndexTransaction(type(of: self).dbExtensionName) - } - - static func asyncRegisterDatabaseExtension(storage: OWSStorage) { - storage.asyncRegister(dbExtensionConfig, withName: dbExtensionName) - } - - enum JobRecordField: String { - case status, label, sortId - } - - static var dbExtensionConfig: YapDatabaseSecondaryIndex { - let setup = YapDatabaseSecondaryIndexSetup() - setup.addColumn(JobRecordField.sortId.rawValue, with: .integer) - setup.addColumn(JobRecordField.status.rawValue, with: .integer) - setup.addColumn(JobRecordField.label.rawValue, with: .text) - - let block: YapDatabaseSecondaryIndexWithObjectBlock = { _, dict, _, _, object in - guard let jobRecord = object as? SSKJobRecord else { - return - } - - dict[JobRecordField.sortId.rawValue] = jobRecord.sortId - dict[JobRecordField.status.rawValue] = jobRecord.status.rawValue - dict[JobRecordField.label.rawValue] = jobRecord.label - } - - let handler = YapDatabaseSecondaryIndexHandler.withObjectBlock(block) - - let options = YapDatabaseSecondaryIndexOptions() - let whitelist = YapWhitelistBlacklist(whitelist: Set([SSKJobRecord.collection()])) - options.allowedCollections = whitelist - - return YapDatabaseSecondaryIndex.init(setup: setup, handler: handler, versionTag: "2", options: options) - } -} - -extension YAPDBJobRecordFinder: JobRecordFinder { - public func enumerateJobRecords(label: String, transaction: YapDatabaseReadTransaction, block: @escaping (JobRecordType, UnsafeMutablePointer) -> Void) { - let queryFormat = String(format: "WHERE %@ = ? ORDER BY %@", JobRecordField.label.rawValue, JobRecordField.sortId.rawValue) - let query = YapDatabaseQuery(string: queryFormat, parameters: [label]) - - guard let ext = self.ext(transaction: transaction) else { - return - } - ext.enumerateKeysAndObjects(matching: query) { _, _, object, stopPointer in - guard let jobRecord = object as? JobRecordType else { - owsFailDebug("expecting jobRecord but found: \(object)") - return - } - block(jobRecord, stopPointer) - } - } - - public func enumerateJobRecords(label: String, status: SSKJobRecordStatus, transaction: YapDatabaseReadTransaction, block: @escaping (JobRecordType, UnsafeMutablePointer) -> Void) { - let queryFormat = String(format: "WHERE %@ = ? AND %@ = ? ORDER BY %@", JobRecordField.status.rawValue, JobRecordField.label.rawValue, JobRecordField.sortId.rawValue) - let query = YapDatabaseQuery(string: queryFormat, parameters: [status.rawValue, label]) - - guard let ext = self.ext(transaction: transaction) else { - return - } - ext.enumerateKeysAndObjects(matching: query) { _, _, object, stopPointer in - guard let jobRecord = object as? JobRecordType else { - owsFailDebug("expecting jobRecord but found: \(object)") - return - } - block(jobRecord, stopPointer) - } - } -} diff --git a/SignalServiceKit/src/Util/ModelReadCache.swift b/SignalServiceKit/src/Util/ModelReadCache.swift index f060844d01..a72d23999e 100644 --- a/SignalServiceKit/src/Util/ModelReadCache.swift +++ b/SignalServiceKit/src/Util/ModelReadCache.swift @@ -408,8 +408,6 @@ private class ModelReadCache *dictionary = [NSUserDefaults standardUserDefaults].dictionaryRepresentation; - for (NSString *key in dictionary) { - id value = dictionary[key]; - OWSAssertDebug(value); - [appUserDefaults setObject:value forKey:key]; - } -} - + (void)removeAll { [NSUserDefaults.standardUserDefaults removeAll]; diff --git a/SignalServiceKit/src/Util/OWSBackupFragment+SDS.swift b/SignalServiceKit/src/Util/OWSBackupFragment+SDS.swift index 6c26ffb47f..1cb80de49b 100644 --- a/SignalServiceKit/src/Util/OWSBackupFragment+SDS.swift +++ b/SignalServiceKit/src/Util/OWSBackupFragment+SDS.swift @@ -392,8 +392,6 @@ public extension OWSBackupFragment { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return OWSBackupFragment.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(BackupFragmentRecord.databaseTableName) WHERE \(backupFragmentColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -424,14 +422,6 @@ public extension OWSBackupFragment { batchSize: UInt, block: @escaping (OWSBackupFragment, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - OWSBackupFragment.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? OWSBackupFragment else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = OWSBackupFragment.grdbFetchCursor(transaction: grdbTransaction) @@ -473,10 +463,6 @@ public extension OWSBackupFragment { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: OWSBackupFragment.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -508,8 +494,6 @@ public extension OWSBackupFragment { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: OWSBackupFragment.collection()) case .grdbRead(let grdbTransaction): return BackupFragmentRecord.ows_fetchCount(grdbTransaction.database) } @@ -519,8 +503,6 @@ public extension OWSBackupFragment { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: OWSBackupFragment.collection()) case .grdbWrite(let grdbTransaction): do { try BackupFragmentRecord.deleteAll(grdbTransaction.database) @@ -569,8 +551,6 @@ public extension OWSBackupFragment { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: OWSBackupFragment.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(BackupFragmentRecord.databaseTableName) WHERE \(backupFragmentColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Util/OWSUserProfile+SDS.swift b/SignalServiceKit/src/Util/OWSUserProfile+SDS.swift index b2d0384e8e..582ab31640 100644 --- a/SignalServiceKit/src/Util/OWSUserProfile+SDS.swift +++ b/SignalServiceKit/src/Util/OWSUserProfile+SDS.swift @@ -472,8 +472,6 @@ public extension OWSUserProfile { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return OWSUserProfile.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(UserProfileRecord.databaseTableName) WHERE \(userProfileColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -504,14 +502,6 @@ public extension OWSUserProfile { batchSize: UInt, block: @escaping (OWSUserProfile, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - OWSUserProfile.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? OWSUserProfile else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = OWSUserProfile.grdbFetchCursor(transaction: grdbTransaction) @@ -553,10 +543,6 @@ public extension OWSUserProfile { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: OWSUserProfile.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -588,8 +574,6 @@ public extension OWSUserProfile { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: OWSUserProfile.collection()) case .grdbRead(let grdbTransaction): return UserProfileRecord.ows_fetchCount(grdbTransaction.database) } @@ -599,8 +583,6 @@ public extension OWSUserProfile { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: OWSUserProfile.collection()) case .grdbWrite(let grdbTransaction): do { try UserProfileRecord.deleteAll(grdbTransaction.database) @@ -649,8 +631,6 @@ public extension OWSUserProfile { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: OWSUserProfile.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(UserProfileRecord.databaseTableName) WHERE \(userProfileColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Util/SSKPreferences.swift b/SignalServiceKit/src/Util/SSKPreferences.swift index 07921c1e50..209b2e309f 100644 --- a/SignalServiceKit/src/Util/SSKPreferences.swift +++ b/SignalServiceKit/src/Util/SSKPreferences.swift @@ -92,26 +92,6 @@ public class SSKPreferences: NSObject { // MARK: - - private static let isYdbMigratedKey = "isYdbMigrated1" - - @objc - public static func isYdbMigrated() -> Bool { - let appUserDefaults = CurrentAppContext().appUserDefaults() - guard let preference = appUserDefaults.object(forKey: isYdbMigratedKey) as? NSNumber else { - return false - } - return preference.boolValue - } - - @objc - public static func setIsYdbMigrated(_ value: Bool) { - let appUserDefaults = CurrentAppContext().appUserDefaults() - appUserDefaults.set(value, forKey: isYdbMigratedKey) - appUserDefaults.synchronize() - } - - // MARK: - - private static let didEverUseYdbKey = "didEverUseYdb" @objc @@ -130,6 +110,24 @@ public class SSKPreferences: NSObject { appUserDefaults.synchronize() } + private static let didDropYdbKey = "didDropYdb" + + @objc + public static func didDropYdb() -> Bool { + let appUserDefaults = CurrentAppContext().appUserDefaults() + guard let preference = appUserDefaults.object(forKey: didDropYdbKey) as? NSNumber else { + return false + } + return preference.boolValue + } + + @objc + public static func setDidDropYdb(_ value: Bool) { + let appUserDefaults = CurrentAppContext().appUserDefaults() + appUserDefaults.set(value, forKey: didDropYdbKey) + appUserDefaults.synchronize() + } + // MARK: - messageRequestInteractionIdEpoch private static let messageRequestInteractionIdEpochKey = "messageRequestInteractionIdEpoch" diff --git a/SignalServiceKit/src/Util/TestModel+SDS.swift b/SignalServiceKit/src/Util/TestModel+SDS.swift index 951e82fbc8..317f903081 100644 --- a/SignalServiceKit/src/Util/TestModel+SDS.swift +++ b/SignalServiceKit/src/Util/TestModel+SDS.swift @@ -420,8 +420,6 @@ public extension TestModel { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return TestModel.ydb_fetch(uniqueId: uniqueId, transaction: ydbTransaction) case .grdbRead(let grdbTransaction): let sql = "SELECT * FROM \(TestModelRecord.databaseTableName) WHERE \(testModelColumn: .uniqueId) = ?" return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction) @@ -452,14 +450,6 @@ public extension TestModel { batchSize: UInt, block: @escaping (TestModel, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - TestModel.ydb_enumerateCollectionObjects(with: ydbTransaction) { (object, stop) in - guard let value = object as? TestModel else { - owsFailDebug("unexpected object: \(type(of: object))") - return - } - block(value, stop) - } case .grdbRead(let grdbTransaction): do { let cursor = TestModel.grdbFetchCursor(transaction: grdbTransaction) @@ -501,10 +491,6 @@ public extension TestModel { batchSize: UInt, block: @escaping (String, UnsafeMutablePointer) -> Void) { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - ydbTransaction.enumerateKeys(inCollection: TestModel.collection()) { (uniqueId, stop) in - block(uniqueId, stop) - } case .grdbRead(let grdbTransaction): grdbEnumerateUniqueIds(transaction: grdbTransaction, sql: """ @@ -536,8 +522,6 @@ public extension TestModel { class func anyCount(transaction: SDSAnyReadTransaction) -> UInt { switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.numberOfKeys(inCollection: TestModel.collection()) case .grdbRead(let grdbTransaction): return TestModelRecord.ows_fetchCount(grdbTransaction.database) } @@ -547,8 +531,6 @@ public extension TestModel { // in their anyWillRemove(), anyDidRemove() methods. class func anyRemoveAllWithoutInstantation(transaction: SDSAnyWriteTransaction) { switch transaction.writeTransaction { - case .yapWrite(let ydbTransaction): - ydbTransaction.removeAllObjects(inCollection: TestModel.collection()) case .grdbWrite(let grdbTransaction): do { try TestModelRecord.deleteAll(grdbTransaction.database) @@ -597,8 +579,6 @@ public extension TestModel { assert(uniqueId.count > 0) switch transaction.readTransaction { - case .yapRead(let ydbTransaction): - return ydbTransaction.hasObject(forKey: uniqueId, inCollection: TestModel.collection()) case .grdbRead(let grdbTransaction): let sql = "SELECT EXISTS ( SELECT 1 FROM \(TestModelRecord.databaseTableName) WHERE \(testModelColumn: .uniqueId) = ? )" let arguments: StatementArguments = [uniqueId] diff --git a/SignalServiceKit/src/Util/UserProfileFinder.swift b/SignalServiceKit/src/Util/UserProfileFinder.swift index 7fac969e8e..5c6228e5cc 100644 --- a/SignalServiceKit/src/Util/UserProfileFinder.swift +++ b/SignalServiceKit/src/Util/UserProfileFinder.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // import Foundation @@ -8,8 +8,6 @@ import GRDB @objc class AnyUserProfileFinder: NSObject { let grdbAdapter = GRDBUserProfileFinder() - let yapdbAdapter = YAPDBSignalServiceAddressIndex() - let yapdbUsernameAdapter = YAPDBUserProfileFinder() } extension AnyUserProfileFinder { @@ -18,8 +16,6 @@ extension AnyUserProfileFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.userProfile(for: address, transaction: transaction) - case .yapRead(let transaction): - return yapdbAdapter.fetchOne(for: address, transaction: transaction) } } @@ -28,9 +24,6 @@ extension AnyUserProfileFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.userProfileForUUID(uuid, transaction: transaction) - case .yapRead: - owsFailDebug("Invalid transaction.") - return nil } } @@ -39,9 +32,6 @@ extension AnyUserProfileFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.userProfileForPhoneNumber(phoneNumber, transaction: transaction) - case .yapRead: - owsFailDebug("Invalid transaction.") - return nil } } @@ -50,8 +40,6 @@ extension AnyUserProfileFinder { switch transaction.readTransaction { case .grdbRead(let transaction): return grdbAdapter.userProfile(forUsername: username.lowercased(), transaction: transaction) - case .yapRead(let transaction): - return yapdbUsernameAdapter.userProfile(forUsername: username.lowercased(), transaction: transaction) } } @@ -60,8 +48,6 @@ extension AnyUserProfileFinder { switch transaction.readTransaction { case .grdbRead(let transaction): grdbAdapter.enumerateMissingAndStaleUserProfiles(transaction: transaction, block: block) - case .yapRead: - owsFail("Invalid database.") } } } @@ -144,51 +130,3 @@ class GRDBUserProfileFinder: NSObject { } } } - -// MARK: - - -@objc -public class YAPDBUserProfileFinder: NSObject { - public static let extensionName = "index_on_username" - private static let usernameKey = "usernameKey" - - @objc - public static func asyncRegisterDatabaseExtensions(_ storage: OWSStorage) { - storage.asyncRegister(extensionConfig(), withName: extensionName) - } - - static func extensionConfig() -> YapDatabaseSecondaryIndex { - let setup = YapDatabaseSecondaryIndexSetup() - setup.addColumn(usernameKey, with: .text) - - let handler = YapDatabaseSecondaryIndexHandler.withObjectBlock { _, dict, _, _, object in - guard let userProfile = object as? OWSUserProfile else { return } - dict[usernameKey] = userProfile.username - } - - return YapDatabaseSecondaryIndex.init(setup: setup, handler: handler, versionTag: "1") - } - - func userProfile(forUsername username: String, transaction: YapDatabaseReadTransaction) -> OWSUserProfile? { - guard let ext = transaction.safeSecondaryIndexTransaction(YAPDBUserProfileFinder.extensionName) else { - owsFailDebug("missing extension") - return nil - } - - let queryFormat = String(format: "WHERE %@ = \"%@\"", YAPDBUserProfileFinder.usernameKey, username) - let query = YapDatabaseQuery(string: queryFormat, parameters: []) - - var matchedProfile: OWSUserProfile? - - ext.enumerateKeysAndObjects(matching: query) { _, _, object, stop in - guard let userProfile = object as? OWSUserProfile else { - owsFailDebug("Unexpected object type") - return - } - matchedProfile = userProfile - stop.pointee = true - } - - return matchedProfile - } -} diff --git a/SignalServiceKit/src/Util/ViewOnceMessages.swift b/SignalServiceKit/src/Util/ViewOnceMessages.swift index a8bd798a81..ae15ac4e3e 100644 --- a/SignalServiceKit/src/Util/ViewOnceMessages.swift +++ b/SignalServiceKit/src/Util/ViewOnceMessages.swift @@ -255,7 +255,6 @@ extension ViewOnceMessageFinder { public class AnyViewOnceMessageFinder { lazy var grdbAdapter = GRDBViewOnceMessageFinder() - lazy var yapAdapter = YAPDBViewOnceMessageFinder() } // MARK: - @@ -265,8 +264,6 @@ extension AnyViewOnceMessageFinder: ViewOnceMessageFinder { switch transaction.readTransaction { case .grdbRead(let grdbRead): grdbAdapter.enumerateAllIncompleteViewOnceMessages(transaction: grdbRead, block: block) - case .yapRead(let yapRead): - yapAdapter.enumerateAllIncompleteViewOnceMessages(transaction: yapRead, block: block) } } } @@ -305,27 +302,3 @@ class GRDBViewOnceMessageFinder: ViewOnceMessageFinder { } } } - -// MARK: - - -class YAPDBViewOnceMessageFinder: ViewOnceMessageFinder { - public func enumerateAllIncompleteViewOnceMessages(transaction: YapDatabaseReadTransaction, block: @escaping EnumerateTSMessageBlock) { - guard let dbView = TSDatabaseView.incompleteViewOnceMessagesDatabaseView(transaction) as? YapDatabaseViewTransaction else { - owsFailDebug("Couldn't load db view.") - return - } - - dbView.safe_enumerateKeysAndObjects(inGroup: TSIncompleteViewOnceMessagesGroup, extensionName: TSIncompleteViewOnceMessagesDatabaseViewExtensionName) { (_: String, _: String, object: Any, _: UInt, stopPointer: UnsafeMutablePointer) in - guard let message = object as? TSMessage else { - owsFailDebug("Invalid database entity: \(type(of: object)).") - return - } - guard message.isViewOnceMessage, - !message.isViewOnceComplete else { - owsFailDebug("expecting incomplete view-once message but found: \(message)") - return - } - block(message, stopPointer) - } - } -} diff --git a/SignalServiceKit/src/Util/YapDatabase+Promise.swift b/SignalServiceKit/src/Util/YapDatabase+Promise.swift deleted file mode 100644 index dd62dba9f8..0000000000 --- a/SignalServiceKit/src/Util/YapDatabase+Promise.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import PromiseKit - -public extension YapDatabaseConnection { - - @objc - func readWritePromise(_ block: @escaping (YapDatabaseReadWriteTransaction) -> Void) -> AnyPromise { - return AnyPromise(readWritePromise(block) as Promise) - } - - func readWritePromise(_ block: @escaping (YapDatabaseReadWriteTransaction) -> Void) -> Promise { - return Promise { resolver in - self.asyncReadWrite(block, completionBlock: { resolver.fulfill(()) }) - } - } - - func read(_ block: @escaping (YapDatabaseReadTransaction) throws -> Void) throws { - var errorToRaise: Error? - - read { transaction in - do { - try block(transaction) - } catch { - errorToRaise = error - } - } - - if let errorToRaise = errorToRaise { - throw errorToRaise - } - } - - func readWrite(_ block: @escaping (YapDatabaseReadWriteTransaction) throws -> Void) throws { - var errorToRaise: Error? - - readWrite { transaction in - do { - try block(transaction) - } catch { - errorToRaise = error - } - } - - if let errorToRaise = errorToRaise { - throw errorToRaise - } - } -} - -public extension YapDatabaseReadTransaction { - func enumerateKeysAndObjects(inCollection collection: String?, using block: @escaping (String, Any, UnsafeMutablePointer) throws -> Void) throws { - var errorToRaise: Error? - self.enumerateKeysAndObjects(inCollection: collection) { key, obj, stopPtr in - do { - try block(key, obj, stopPtr) - } catch { - stopPtr.pointee = true - errorToRaise = error - } - } - if let errorToRaise = errorToRaise { - throw errorToRaise - } - } -} diff --git a/SignalServiceKit/src/Util/YapDatabaseViewTransaction+OWS.h b/SignalServiceKit/src/Util/YapDatabaseViewTransaction+OWS.h deleted file mode 100644 index 73ff29a6b4..0000000000 --- a/SignalServiceKit/src/Util/YapDatabaseViewTransaction+OWS.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface YapDatabaseViewTransaction (OWS) - -- (void)safe_enumerateKeysAndObjectsInGroup:(NSString *)group - extensionName:(NSString *)extensionName - withOptions:(NSEnumerationOptions)options - usingBlock:(void (^)(NSString *collection, - NSString *key, - id object, - NSUInteger index, - BOOL *stop))block; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Util/YapDatabaseViewTransaction+OWS.m b/SignalServiceKit/src/Util/YapDatabaseViewTransaction+OWS.m deleted file mode 100644 index 174464b72d..0000000000 --- a/SignalServiceKit/src/Util/YapDatabaseViewTransaction+OWS.m +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSPrimaryStorage.h" -#import "YapDatabaseViewTransaction+OWS.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation YapDatabaseViewTransaction (OWS) - -- (void)safe_enumerateKeysAndObjectsInGroup:(NSString *)group - extensionName:(NSString *)extensionName - withOptions:(NSEnumerationOptions)options - usingBlock:(void (^)(NSString *collection, - NSString *key, - id object, - NSUInteger index, - BOOL *stop))block -{ - if (group.length < 1) { - OWSFail(@"Invalid group."); - return; - } - - [self - enumerateKeysAndObjectsInGroup:group - withOptions:options - usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { - if (collection.length < 1) { - // Apparently, when YDB extensions are corrupt, - // they can return nil collection. - [OWSPrimaryStorage incrementVersionOfDatabaseExtension:extensionName]; - if (SSKFeatureFlags.strictYDBExtensions) { - OWSFail(@"Invalid collection."); - } else { - OWSFailDebug(@"Invalid collection."); - } - return; - } - if (key.length < 1) { - [OWSPrimaryStorage incrementVersionOfDatabaseExtension:extensionName]; - if (SSKFeatureFlags.strictYDBExtensions) { - OWSFail(@"Invalid key."); - } else { - OWSFailDebug(@"Invalid key."); - } - return; - } - if (object == nil) { - [OWSPrimaryStorage incrementVersionOfDatabaseExtension:extensionName]; - // The other checks OWSFail(), but here we do - // not fail in prod and just skip this object. - if (SSKFeatureFlags.strictYDBExtensions) { - OWSFail(@"Invalid object."); - } else { - OWSFailDebug(@"Invalid object."); - } - return; - } - if (stop == nil) { - [OWSPrimaryStorage incrementVersionOfDatabaseExtension:extensionName]; - OWSFail(@"Invalid stop."); - return; - } - - block(collection, key, object, index, stop); - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/tests/Messages/MessageProcessingIntegrationTest.swift b/SignalServiceKit/tests/Messages/MessageProcessingIntegrationTest.swift index b06b363770..43deaf8982 100644 --- a/SignalServiceKit/tests/Messages/MessageProcessingIntegrationTest.swift +++ b/SignalServiceKit/tests/Messages/MessageProcessingIntegrationTest.swift @@ -47,7 +47,6 @@ class MessageProcessingIntegrationTest: SSKBaseTestSwift { // MARK: - Tests func test_contactMessage_e164AndUuidEnvelope() { - write { transaction in try! self.runner.initialize(senderClient: self.bobClient, recipientClient: self.localClient, diff --git a/SignalServiceKit/tests/Messages/OWSIncomingMessageFinderTest.m b/SignalServiceKit/tests/Messages/OWSIncomingMessageFinderTest.m deleted file mode 100644 index 5471baca0f..0000000000 --- a/SignalServiceKit/tests/Messages/OWSIncomingMessageFinderTest.m +++ /dev/null @@ -1,134 +0,0 @@ -// -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. -// - -#import "OWSDevice.h" -#import "OWSIncomingMessageFinder.h" -#import "SSKBaseTestObjC.h" -#import "TSContactThread.h" -#import "TSIncomingMessage.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSIncomingMessageFinder (Testing) - -- (void)registerExtension; - -@end - -@interface OWSIncomingMessageFinderTest : SSKBaseTestObjC - -@property (nonatomic) SignalServiceAddress *sourceAddress; -@property (nonatomic) TSThread *thread; -@property (nonatomic) OWSIncomingMessageFinder *finder; - -@end - -@implementation OWSIncomingMessageFinderTest - -- (void)setUp -{ - [super setUp]; - self.sourceAddress = [[SignalServiceAddress alloc] initWithPhoneNumber:@"+19999999999"]; - self.thread = [TSContactThread getOrCreateThreadWithContactAddress:self.sourceAddress]; - self.finder = [OWSIncomingMessageFinder new]; -} - -- (void)tearDown -{ - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - - -- (void)createIncomingMessageWithTimestamp:(uint64_t)timestamp - authorAddress:(SignalServiceAddress *)authorAddress - sourceDeviceId:(uint32_t)sourceDeviceId -{ - TSIncomingMessageBuilder *incomingMessageBuilder = - [TSIncomingMessageBuilder incomingMessageBuilderWithThread:self.thread messageBody:@"foo"]; - incomingMessageBuilder.timestamp = timestamp; - incomingMessageBuilder.authorAddress = authorAddress; - incomingMessageBuilder.sourceDeviceId = sourceDeviceId; - TSIncomingMessage *incomingMessage = [incomingMessageBuilder build]; - [self writeWithBlock:^(SDSAnyWriteTransaction *transaction) { - [incomingMessage anyInsertWithTransaction:transaction]; - }]; -} - -- (void)testExistingMessages -{ - - uint64_t timestamp = 1234; - __block BOOL result; - - [self readWithBlock:^(SDSAnyReadTransaction *transaction) { - result = [InteractionFinder existsIncomingMessageWithTimestamp:timestamp - address:self.sourceAddress - sourceDeviceId:OWSDevicePrimaryDeviceId - transaction:transaction]; - }]; - - - // Sanity check. - XCTAssertFalse(result); - - // Different timestamp - [self createIncomingMessageWithTimestamp:timestamp + 1 - authorAddress:self.sourceAddress - sourceDeviceId:OWSDevicePrimaryDeviceId]; - - [self readWithBlock:^(SDSAnyReadTransaction *transaction) { - result = [InteractionFinder existsIncomingMessageWithTimestamp:timestamp - address:self.sourceAddress - sourceDeviceId:OWSDevicePrimaryDeviceId - transaction:transaction]; - }]; - - XCTAssertFalse(result); - - // Different authorId - [self createIncomingMessageWithTimestamp:timestamp - authorAddress:[[SignalServiceAddress alloc] initWithPhoneNumber:@"some-other-address"] - sourceDeviceId:OWSDevicePrimaryDeviceId]; - - [self readWithBlock:^(SDSAnyReadTransaction *transaction) { - result = [InteractionFinder existsIncomingMessageWithTimestamp:timestamp - address:self.sourceAddress - sourceDeviceId:OWSDevicePrimaryDeviceId - transaction:transaction]; - }]; - XCTAssertFalse(result); - - // Different device - [self createIncomingMessageWithTimestamp:timestamp - authorAddress:self.sourceAddress - sourceDeviceId:OWSDevicePrimaryDeviceId + 1]; - - [self readWithBlock:^(SDSAnyReadTransaction *transaction) { - result = [InteractionFinder existsIncomingMessageWithTimestamp:timestamp - address:self.sourceAddress - sourceDeviceId:OWSDevicePrimaryDeviceId - transaction:transaction]; - }]; - XCTAssertFalse(result); - - // The real deal... - [self createIncomingMessageWithTimestamp:timestamp - authorAddress:self.sourceAddress - sourceDeviceId:OWSDevicePrimaryDeviceId]; - - [self readWithBlock:^(SDSAnyReadTransaction *transaction) { - result = [InteractionFinder existsIncomingMessageWithTimestamp:timestamp - address:self.sourceAddress - sourceDeviceId:OWSDevicePrimaryDeviceId - transaction:transaction]; - }]; - - XCTAssertTrue(result); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/tests/SSKBaseTestObjC.h b/SignalServiceKit/tests/SSKBaseTestObjC.h index c8e0b50260..17e674979e 100644 --- a/SignalServiceKit/tests/SSKBaseTestObjC.h +++ b/SignalServiceKit/tests/SSKBaseTestObjC.h @@ -1,10 +1,9 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. // #import #import -#import NS_ASSUME_NONNULL_BEGIN @@ -18,9 +17,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)readWithBlock:(void (^)(SDSAnyReadTransaction *transaction))block; - (void)writeWithBlock:(void (^)(SDSAnyWriteTransaction *transaction))block; -- (void)yapReadWithBlock:(void (^)(YapDatabaseReadTransaction *transaction))block; -- (void)yapWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block; - @end #endif diff --git a/SignalServiceKit/tests/SSKBaseTestObjC.m b/SignalServiceKit/tests/SSKBaseTestObjC.m index 2eb2a22dd2..49a199f0f8 100644 --- a/SignalServiceKit/tests/SSKBaseTestObjC.m +++ b/SignalServiceKit/tests/SSKBaseTestObjC.m @@ -3,7 +3,6 @@ // #import "SSKBaseTestObjC.h" -#import "OWSPrimaryStorage.h" #import "SSKEnvironment.h" #import "TestAppContext.h" #import @@ -58,20 +57,6 @@ NS_ASSUME_NONNULL_BEGIN DatabaseStorageWrite(SDSDatabaseStorage.shared, block); } -- (void)yapReadWithBlock:(void (^)(YapDatabaseReadTransaction *transaction))block -{ - OWSAssert(block); - - [[SSKEnvironment.shared.primaryStorage newDatabaseConnection] readWithBlock:block]; -} - -- (void)yapWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block -{ - OWSAssert(block); - - [[SSKEnvironment.shared.primaryStorage newDatabaseConnection] readWriteWithBlock:block]; -} - @end #endif diff --git a/SignalServiceKit/tests/SSKBaseTestSwift.swift b/SignalServiceKit/tests/SSKBaseTestSwift.swift index 540e89bcf1..24000b4b1e 100644 --- a/SignalServiceKit/tests/SSKBaseTestSwift.swift +++ b/SignalServiceKit/tests/SSKBaseTestSwift.swift @@ -50,31 +50,4 @@ public class SSKBaseTestSwift: XCTestCase { public func asyncWrite(_ block: @escaping (SDSAnyWriteTransaction) -> Void) { return databaseStorage.asyncWrite(block: block) } - - @objc - public func yapRead(_ block: @escaping (YapDatabaseReadTransaction) -> Void) { - guard let primaryStorage = primaryStorage else { - XCTFail("Missing primaryStorage.") - return - } - return primaryStorage.dbReadConnection.read(block) - } - - @objc - public func yapWrite(_ block: @escaping (YapDatabaseReadWriteTransaction) -> Void) { - guard let primaryStorage = primaryStorage else { - XCTFail("Missing primaryStorage.") - return - } - return primaryStorage.dbReadWriteConnection.readWrite(block) - } - - @objc - public func yapAsyncWrite(_ block: @escaping (YapDatabaseReadWriteTransaction) -> Void) { - guard let primaryStorage = primaryStorage else { - XCTFail("Missing primaryStorage.") - return - } - return primaryStorage.dbReadWriteConnection.asyncReadWrite(block) - } } diff --git a/SignalServiceKit/tests/Storage/InteractionFinderTest.swift b/SignalServiceKit/tests/Storage/InteractionFinderTest.swift index 3b05656aed..786c6f588f 100644 --- a/SignalServiceKit/tests/Storage/InteractionFinderTest.swift +++ b/SignalServiceKit/tests/Storage/InteractionFinderTest.swift @@ -10,8 +10,6 @@ class InteractionFinderTest: SSKBaseTestSwift { override func setUp() { super.setUp() - - storageCoordinator.useGRDBForTests() } func testInteractions() { diff --git a/SignalServiceKit/tests/Storage/SDSDatabaseStorageObservationTest.swift b/SignalServiceKit/tests/Storage/SDSDatabaseStorageObservationTest.swift index de1014a894..d9b4b3b060 100644 --- a/SignalServiceKit/tests/Storage/SDSDatabaseStorageObservationTest.swift +++ b/SignalServiceKit/tests/Storage/SDSDatabaseStorageObservationTest.swift @@ -135,12 +135,7 @@ class SDSDatabaseStorageObservationTest: SSKBaseTestSwift { XCTAssertTrue(lastChange.didUpdate(keyValueStore: keyValueStore)) // Note: For GRDB, didUpdate(keyValueStore:) currently returns true // if any key value stores was updated. - if self.storageCoordinator.state == .YDB || - self.storageCoordinator.state == .ydbTests { - XCTAssertFalse(lastChange.didUpdate(keyValueStore: otherKeyValueStore)) - } else { - XCTAssertTrue(lastChange.didUpdate(keyValueStore: otherKeyValueStore)) - } + XCTAssertTrue(lastChange.didUpdate(keyValueStore: otherKeyValueStore)) } mockObserver.clear() @@ -317,12 +312,7 @@ class SDSDatabaseStorageObservationTest: SSKBaseTestSwift { XCTAssertTrue(lastChange.didUpdate(keyValueStore: keyValueStore)) // Note: For GRDB, didUpdate(keyValueStore:) currently returns true // if any key value stores was updated. - if self.storageCoordinator.state == .YDB || - self.storageCoordinator.state == .ydbTests { - XCTAssertFalse(lastChange.didUpdate(keyValueStore: otherKeyValueStore)) - } else { - XCTAssertTrue(lastChange.didUpdate(keyValueStore: otherKeyValueStore)) - } + XCTAssertTrue(lastChange.didUpdate(keyValueStore: otherKeyValueStore)) } mockObserver.clear() diff --git a/SignalServiceKit/tests/Storage/TestModelTests.swift b/SignalServiceKit/tests/Storage/TestModelTests.swift index fb678ead86..fe2dc5f635 100644 --- a/SignalServiceKit/tests/Storage/TestModelTests.swift +++ b/SignalServiceKit/tests/Storage/TestModelTests.swift @@ -16,12 +16,7 @@ class TestModelTests: SSKBaseTestSwift { writeModel.anyInsert(transaction: transaction) let readModel = TestModel.anyFetch(uniqueId: writeModel.uniqueId, transaction: transaction)! - if self.storageCoordinator.state == .YDB || - self.storageCoordinator.state == .ydbTests { - XCTAssertTrue(writeModel === readModel) - } else { - XCTAssertFalse(writeModel === readModel) - } + XCTAssertFalse(writeModel === readModel) XCTAssertEqual(0, readModel.doubleValue) XCTAssertEqual(0, readModel.floatValue) XCTAssertEqual(0, readModel.uint64Value) @@ -54,12 +49,7 @@ class TestModelTests: SSKBaseTestSwift { } let readModel = TestModel.anyFetch(uniqueId: writeModel.uniqueId, transaction: transaction)! - if self.storageCoordinator.state == .YDB || - self.storageCoordinator.state == .ydbTests { - XCTAssertTrue(writeModel === readModel) - } else { - XCTAssertFalse(writeModel === readModel) - } + XCTAssertFalse(writeModel === readModel) XCTAssertEqual(1, readModel.doubleValue) XCTAssertEqual(1, readModel.floatValue) XCTAssertEqual(1, readModel.uint64Value) @@ -112,12 +102,7 @@ class TestModelTests: SSKBaseTestSwift { } let readModel = TestModel.anyFetch(uniqueId: writeModel.uniqueId, transaction: transaction)! - if self.storageCoordinator.state == .YDB || - self.storageCoordinator.state == .ydbTests { - XCTAssertTrue(writeModel === readModel) - } else { - XCTAssertFalse(writeModel === readModel) - } + XCTAssertFalse(writeModel === readModel) XCTAssertEqual(Double.greatestFiniteMagnitude, readModel.doubleValue) XCTAssertEqual(Float.greatestFiniteMagnitude, readModel.floatValue) XCTAssertEqual(uint64Max, readModel.uint64Value) @@ -146,12 +131,7 @@ class TestModelTests: SSKBaseTestSwift { } let readModel = TestModel.anyFetch(uniqueId: writeModel.uniqueId, transaction: transaction)! - if self.storageCoordinator.state == .YDB || - self.storageCoordinator.state == .ydbTests { - XCTAssertTrue(writeModel === readModel) - } else { - XCTAssertFalse(writeModel === readModel) - } + XCTAssertFalse(writeModel === readModel) XCTAssertEqual(Double.leastNormalMagnitude, readModel.doubleValue) XCTAssertEqual(Float.leastNormalMagnitude, readModel.floatValue) XCTAssertEqual(UInt64.min, readModel.uint64Value) @@ -173,12 +153,7 @@ class TestModelTests: SSKBaseTestSwift { } let readModel = TestModel.anyFetch(uniqueId: writeModel.uniqueId, transaction: transaction)! - if self.storageCoordinator.state == .YDB || - self.storageCoordinator.state == .ydbTests { - XCTAssertTrue(writeModel === readModel) - } else { - XCTAssertFalse(writeModel === readModel) - } + XCTAssertFalse(writeModel === readModel) // This date value will NOT be truncated during the roundtrip. // NSDate is backed by NSTimeInterval (seconds as double) and we // serialiuze using TimeInterval/timeIntervalSince1970. diff --git a/SignalShareExtension/ShareViewController.swift b/SignalShareExtension/ShareViewController.swift index 0352e86d14..fb19137247 100644 --- a/SignalShareExtension/ShareViewController.swift +++ b/SignalShareExtension/ShareViewController.swift @@ -64,11 +64,8 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed return } - // If we haven't migrated the database file to the shared data - // directory we can't load it, and therefore can't init TSSPrimaryStorage, - // and therefore don't want to setup most of our machinery (Environment, - // most of the singletons, etc.). We just want to show an error view and - // abort. + // There may be database migrations that only the main app can perform. + // If so, we just want to show an error view and abort. isReadyForAppExtensions = OWSPreferences.isReadyForAppExtensions() guard isReadyForAppExtensions else { showNotReadyView()