Removed all the old Storage classes and YapDB extensions
Removed the AppUpdateNag code (unused) Removed the Mantle dependency
This commit is contained in:
parent
18d833f152
commit
59696f7d2c
|
@ -1,17 +1,6 @@
|
|||
import Foundation
|
||||
import SessionUtilitiesKit
|
||||
|
||||
@objc
|
||||
public final class SNMessagingKitConfiguration : NSObject {
|
||||
public let storage: SessionMessagingKitStorageProtocol
|
||||
|
||||
@objc public static var shared: SNMessagingKitConfiguration!
|
||||
|
||||
fileprivate init(storage: SessionMessagingKitStorageProtocol) {
|
||||
self.storage = storage
|
||||
}
|
||||
}
|
||||
|
||||
public enum SNMessagingKit { // Just to make the external API nice
|
||||
public static func migrations() -> TargetMigrations {
|
||||
return TargetMigrations(
|
||||
|
@ -28,7 +17,7 @@ public enum SNMessagingKit { // Just to make the external API nice
|
|||
)
|
||||
}
|
||||
|
||||
public static func configure(storage: SessionMessagingKitStorageProtocol) {
|
||||
public static func configure() {
|
||||
// Configure the job executors
|
||||
JobRunner.add(executor: DisappearingMessagesJob.self, for: .disappearingMessages)
|
||||
JobRunner.add(executor: FailedMessageSendsJob.self, for: .failedMessageSends)
|
||||
|
@ -42,7 +31,5 @@ public enum SNMessagingKit { // Just to make the external API nice
|
|||
JobRunner.add(executor: SendReadReceiptsJob.self, for: .sendReadReceipts)
|
||||
JobRunner.add(executor: AttachmentDownloadJob.self, for: .attachmentDownload)
|
||||
JobRunner.add(executor: AttachmentUploadJob.self, for: .attachmentUpload)
|
||||
|
||||
SNMessagingKitConfiguration.shared = SNMessagingKitConfiguration(storage: storage)
|
||||
}
|
||||
}
|
||||
|
|
2
Podfile
2
Podfile
|
@ -21,7 +21,6 @@ abstract_target 'GlobalDependencies' do
|
|||
pod 'PureLayout', '~> 3.1.8'
|
||||
pod 'NVActivityIndicatorView'
|
||||
pod 'YYImage', git: 'https://github.com/signalapp/YYImage'
|
||||
pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master'
|
||||
pod 'ZXingObjC'
|
||||
pod 'DifferenceKit'
|
||||
end
|
||||
|
@ -38,7 +37,6 @@ abstract_target 'GlobalDependencies' do
|
|||
abstract_target 'ExtendedDependencies' do
|
||||
pod 'AFNetworking'
|
||||
pod 'PureLayout', '~> 3.1.8'
|
||||
pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master'
|
||||
|
||||
target 'SessionShareExtension' do
|
||||
pod 'NVActivityIndicatorView'
|
||||
|
|
13
Podfile.lock
13
Podfile.lock
|
@ -29,9 +29,6 @@ PODS:
|
|||
- DifferenceKit/Core
|
||||
- GRDB.swift/SQLCipher (5.24.1):
|
||||
- SQLCipher (>= 3.4.0)
|
||||
- Mantle (2.1.0):
|
||||
- Mantle/extobjc (= 2.1.0)
|
||||
- Mantle/extobjc (2.1.0)
|
||||
- NVActivityIndicatorView (5.1.1):
|
||||
- NVActivityIndicatorView/Base (= 5.1.1)
|
||||
- NVActivityIndicatorView/Base (5.1.1)
|
||||
|
@ -133,7 +130,6 @@ DEPENDENCIES:
|
|||
- Curve25519Kit (from `https://github.com/signalapp/Curve25519Kit.git`)
|
||||
- DifferenceKit
|
||||
- GRDB.swift/SQLCipher
|
||||
- Mantle (from `https://github.com/signalapp/Mantle`, branch `signal-master`)
|
||||
- NVActivityIndicatorView
|
||||
- PromiseKit
|
||||
- PureLayout (~> 3.1.8)
|
||||
|
@ -168,9 +164,6 @@ SPEC REPOS:
|
|||
EXTERNAL SOURCES:
|
||||
Curve25519Kit:
|
||||
:git: https://github.com/signalapp/Curve25519Kit.git
|
||||
Mantle:
|
||||
:branch: signal-master
|
||||
:git: https://github.com/signalapp/Mantle
|
||||
SignalCoreKit:
|
||||
:branch: session-version
|
||||
:git: https://github.com/oxen-io/session-ios-core-kit
|
||||
|
@ -184,9 +177,6 @@ CHECKOUT OPTIONS:
|
|||
Curve25519Kit:
|
||||
:commit: 4fc1c10e98fff2534b5379a9bb587430fdb8e577
|
||||
:git: https://github.com/signalapp/Curve25519Kit.git
|
||||
Mantle:
|
||||
:commit: e7e46253bb01ce39525d90aa69ed9e85e758bfc4
|
||||
:git: https://github.com/signalapp/Mantle
|
||||
SignalCoreKit:
|
||||
:commit: 4590c2737a2b5dc0ef4ace9f9019b581caccc1de
|
||||
:git: https://github.com/oxen-io/session-ios-core-kit
|
||||
|
@ -204,7 +194,6 @@ SPEC CHECKSUMS:
|
|||
Curve25519Kit: e63f9859ede02438ae3defc5e1a87e09d1ec7ee6
|
||||
DifferenceKit: 5659c430bb7fe45876fa32ce5cba5d6167f0c805
|
||||
GRDB.swift: b3180ce2135fc06a453297889b746b1478c4d8c7
|
||||
Mantle: 2fa750afa478cd625a94230fbf1c13462f29395b
|
||||
NVActivityIndicatorView: 1f6c5687f1171810aa27a3296814dc2d7dec3667
|
||||
OpenSSL-Universal: e7311447fd2419f57420c79524b641537387eff2
|
||||
PromiseKit: 3b2b6995e51a954c46dbc550ce3da44fbfb563c5
|
||||
|
@ -219,6 +208,6 @@ SPEC CHECKSUMS:
|
|||
YYImage: f1ddd15ac032a58b78bbed1e012b50302d318331
|
||||
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
|
||||
|
||||
PODFILE CHECKSUM: 9715c163fab54d487be0c32357d6d1729aa96a7b
|
||||
PODFILE CHECKSUM: 05dc0000aee6d863406fc684884935594fcf14fa
|
||||
|
||||
COCOAPODS: 1.11.2
|
||||
|
|
|
@ -107,7 +107,6 @@
|
|||
4C9CA25D217E676900607C63 /* ZXingObjC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C9CA25C217E676900607C63 /* ZXingObjC.framework */; };
|
||||
4CA46F4C219CCC630038ABDE /* CaptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA46F4B219CCC630038ABDE /* CaptionView.swift */; };
|
||||
4CA485BB2232339F004B9E7D /* PhotoCaptureViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */; };
|
||||
4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */; };
|
||||
4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC613352227A00400E21A3A /* ConversationSearch.swift */; };
|
||||
70377AAB1918450100CAF501 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70377AAA1918450100CAF501 /* MobileCoreServices.framework */; };
|
||||
768A1A2B17FC9CD300E00ED8 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 768A1A2A17FC9CD300E00ED8 /* libz.dylib */; };
|
||||
|
@ -176,8 +175,6 @@
|
|||
B879D449247E1BE300DB3608 /* PathVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B879D448247E1BE300DB3608 /* PathVC.swift */; };
|
||||
B87EF17126367CF800124B3C /* FileServerAPIV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B87EF17026367CF800124B3C /* FileServerAPIV2.swift */; };
|
||||
B87EF18126377A1D00124B3C /* Features.swift in Sources */ = {isa = PBXBuildFile; fileRef = B87EF18026377A1D00124B3C /* Features.swift */; };
|
||||
B8856CA8256F0F42001CE70E /* OWSBackupFragment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB07255A580700E217F9 /* OWSBackupFragment.m */; };
|
||||
B8856CB1256F0F47001CE70E /* OWSBackupFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */; };
|
||||
B8856CF7256F105E001CE70E /* OWSAudioPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
B8856D08256F10F1001CE70E /* DeviceSleepManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */; };
|
||||
|
@ -194,7 +191,6 @@
|
|||
B8856DF8256F1633001CE70E /* NSString+SSK.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB12255A580800E217F9 /* NSString+SSK.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
B8856E09256F1676001CE70E /* UIDevice+featureSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */; };
|
||||
B8856E1A256F1700001CE70E /* OWSMath.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB14255A580800E217F9 /* OWSMath.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
B8856E33256F18D5001CE70E /* OWSStorage+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
B8856ECE256F1E58001CE70E /* OWSPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF308255B6DBE007E1867 /* OWSPreferences.m */; };
|
||||
B8856ED7256F1EB4001CE70E /* OWSPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B886B4A62398B23E00211ABE /* QRCodeVC.swift */; };
|
||||
|
@ -276,8 +272,6 @@
|
|||
C32C5B51256DC219003C73A2 /* NSNotificationCenter+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C32C5C3D256DCBAF003C73A2 /* AppReadiness.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB75255A581000E217F9 /* AppReadiness.m */; };
|
||||
C32C5C46256DCBB2003C73A2 /* AppReadiness.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB01255A580700E217F9 /* AppReadiness.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */; };
|
||||
C32C5CF0256DD3E4003C73A2 /* Storage+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */; };
|
||||
C32C5D19256DD493003C73A2 /* LinkPreviewDraft.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA8255A581500E217F9 /* LinkPreviewDraft.swift */; };
|
||||
C32C5D83256DD5B6003C73A2 /* SSKKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */; };
|
||||
C32C5DBF256DD743003C73A2 /* ClosedGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */; };
|
||||
|
@ -286,16 +280,6 @@
|
|||
C32C5DD2256DD9E5003C73A2 /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFD255A580600E217F9 /* LRUCache.swift */; };
|
||||
C32C5DDB256DD9FF003C73A2 /* ContentProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB68255A580F00E217F9 /* ContentProxy.swift */; };
|
||||
C32C5E0C256DDAFA003C73A2 /* NSRegularExpression+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */; };
|
||||
C32C5E5B256DDF45003C73A2 /* OWSStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB1255A580000E217F9 /* OWSStorage.m */; };
|
||||
C32C5E64256DDFD6003C73A2 /* OWSStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFE255A580600E217F9 /* OWSStorage.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C32C5E75256DE020003C73A2 /* YapDatabaseTransaction+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */; };
|
||||
C32C5E7E256DE023003C73A2 /* YapDatabaseTransaction+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C32C5E97256DE0CB003C73A2 /* OWSPrimaryStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */; };
|
||||
C32C5EA0256DE0D6003C73A2 /* OWSPrimaryStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C32C5EDC256DF501003C73A2 /* YapDatabaseConnection+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */; };
|
||||
C32C5EE5256DF506003C73A2 /* YapDatabaseConnection+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C32C5EEE256DF54E003C73A2 /* TSDatabaseView.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB46255A580C00E217F9 /* TSDatabaseView.m */; };
|
||||
C32C5EF7256DF567003C73A2 /* TSDatabaseView.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C32C5FBB256E0206003C73A2 /* OWSBackgroundTask.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */; };
|
||||
C32C5FC4256E0209003C73A2 /* OWSBackgroundTask.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C32C600F256E07F5003C73A2 /* NSUserDefaults+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB77255A581000E217F9 /* NSUserDefaults+OWS.m */; };
|
||||
|
@ -331,7 +315,6 @@
|
|||
C33FD9C2255A54EF00E217F9 /* SessionMessagingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A6F025539DE700C340D1 /* SessionMessagingKit.framework */; };
|
||||
C33FD9C4255A54EF00E217F9 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; };
|
||||
C33FD9C5255A54EF00E217F9 /* SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */; };
|
||||
C33FDC27255A581F00E217F9 /* YapDatabase+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */; };
|
||||
C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */; };
|
||||
C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8B255A57FD00E217F9 /* AppVersion.m */; };
|
||||
C33FDC50255A582000E217F9 /* OWSDispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA96255A57FE00E217F9 /* OWSDispatch.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
|
@ -475,8 +458,6 @@
|
|||
C3A01E05261D24C400290BEB /* public-loki-foundation.der in Resources */ = {isa = PBXBuildFile; fileRef = C3A01E02261D24C400290BEB /* public-loki-foundation.der */; };
|
||||
C3A01E06261D24C400290BEB /* storage-seed-1.der in Resources */ = {isa = PBXBuildFile; fileRef = C3A01E03261D24C400290BEB /* storage-seed-1.der */; };
|
||||
C3A01E07261D24C400290BEB /* storage-seed-3.der in Resources */ = {isa = PBXBuildFile; fileRef = C3A01E04261D24C400290BEB /* storage-seed-3.der */; };
|
||||
C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */; };
|
||||
C3A3A12B256E1AD5004D228D /* TSDatabaseSecondaryIndexes.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3A3A171256E1D25004D228D /* SSKReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */; };
|
||||
C3A71D0B2558989C0043A11F /* MessageWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D0A2558989C0043A11F /* MessageWrapper.swift */; };
|
||||
C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D1C25589AC30043A11F /* WebSocketProto.swift */; };
|
||||
|
@ -490,7 +471,6 @@
|
|||
C3AAFFF225AE99710089E6DD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3AAFFF125AE99710089E6DD /* AppDelegate.swift */; };
|
||||
C3ADC66126426688005F1414 /* ShareVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ADC66026426688005F1414 /* ShareVC.swift */; };
|
||||
C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE0752554CDA60050F1E3 /* Configuration.swift */; };
|
||||
C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE07F2554CDD70050F1E3 /* Storage.swift */; };
|
||||
C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D62553860B00C340D1 /* Promise+Retrying.swift */; };
|
||||
C3BBE0A82554D4DE0050F1E3 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D92553860B00C340D1 /* JSON.swift */; };
|
||||
C3BBE0A92554D4DE0050F1E3 /* HTTP.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5BC255385EE00C340D1 /* HTTP.swift */; };
|
||||
|
@ -539,10 +519,6 @@
|
|||
C3D9E38A256760390040E4F3 /* OWSFileSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAB255A581500E217F9 /* OWSFileSystem.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3D9E39B256763C20040E4F3 /* AppContext.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB85255A581100E217F9 /* AppContext.m */; };
|
||||
C3D9E3A4256763DE0040E4F3 /* AppContext.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB8A255A581200E217F9 /* AppContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3D9E3C925676AF30040E4F3 /* TSYapDatabaseObject.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */; };
|
||||
C3D9E3FA25676BCE0040E4F3 /* TSYapDatabaseObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3D9E41525676C320040E4F3 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB36255A580B00E217F9 /* Storage.swift */; };
|
||||
C3D9E41F25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D9E41E25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift */; };
|
||||
C3D9E43125676D3D0040E4F3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D9E43025676D3D0040E4F3 /* Configuration.swift */; };
|
||||
C3D9E4C02567767F0040E4F3 /* DataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB6255A581600E217F9 /* DataSource.m */; };
|
||||
C3D9E4D12567777D0040E4F3 /* OWSMediaUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */; };
|
||||
|
@ -989,7 +965,6 @@
|
|||
4C9CA25C217E676900607C63 /* ZXingObjC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ZXingObjC.framework; path = ThirdParty/Carthage/Build/iOS/ZXingObjC.framework; sourceTree = "<group>"; };
|
||||
4CA46F4B219CCC630038ABDE /* CaptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaptionView.swift; sourceTree = "<group>"; };
|
||||
4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCaptureViewController.swift; sourceTree = "<group>"; };
|
||||
4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdateNag.swift; sourceTree = "<group>"; };
|
||||
4CC613352227A00400E21A3A /* ConversationSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearch.swift; sourceTree = "<group>"; };
|
||||
5A3F440C6CC32A23AD67A2FD /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionUtilitiesKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionUtilitiesKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionUtilitiesKit.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
5B7FDA4BA2DDFF4612600FB8 /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SignalUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SignalUtilitiesKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SignalUtilitiesKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SignalUtilitiesKit.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
|
@ -1147,7 +1122,6 @@
|
|||
B8D0A26825E4A2C200C1835E /* Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Onboarding.swift; sourceTree = "<group>"; };
|
||||
B8D84EA225DF745A005A043E /* LinkPreviewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkPreviewState.swift; sourceTree = "<group>"; };
|
||||
B8D84ECE25E3108A005A043E /* ExpandingAttachmentsButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandingAttachmentsButton.swift; sourceTree = "<group>"; };
|
||||
B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+OpenGroups.swift"; sourceTree = "<group>"; };
|
||||
B8EB20E6263F7E4B00773E52 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
B8EB20ED2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+OpenGroupInvitation.swift"; sourceTree = "<group>"; };
|
||||
B8EB20EF2640F7F000773E52 /* OpenGroupInvitationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupInvitationView.swift; sourceTree = "<group>"; };
|
||||
|
@ -1190,62 +1164,44 @@
|
|||
C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SignalUtilitiesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C33FD9AD255A548A00E217F9 /* SignalUtilitiesKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SignalUtilitiesKit.h; sourceTree = "<group>"; };
|
||||
C33FD9AE255A548A00E217F9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSPrimaryStorage.h; sourceTree = "<group>"; };
|
||||
C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "YapDatabase+Promise.swift"; sourceTree = "<group>"; };
|
||||
C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReachabilityManager.swift; sourceTree = "<group>"; };
|
||||
C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ECKeyPair+Hexadecimal.swift"; sourceTree = "<group>"; };
|
||||
C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSRegularExpression+SSK.swift"; sourceTree = "<group>"; };
|
||||
C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicators.swift; sourceTree = "<group>"; };
|
||||
C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YapDatabaseTransaction+OWS.h"; sourceTree = "<group>"; };
|
||||
C33FDA8B255A57FD00E217F9 /* AppVersion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppVersion.m; sourceTree = "<group>"; };
|
||||
C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFileSystem.m; sourceTree = "<group>"; };
|
||||
C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSYapDatabaseObject.m; sourceTree = "<group>"; };
|
||||
C33FDA96255A57FE00E217F9 /* OWSDispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDispatch.h; sourceTree = "<group>"; };
|
||||
C33FDA99255A57FE00E217F9 /* OutageDetection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutageDetection.swift; sourceTree = "<group>"; };
|
||||
C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReverseDispatchQueue.swift; sourceTree = "<group>"; };
|
||||
C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSYapDatabaseObject.h; sourceTree = "<group>"; };
|
||||
C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BuildConfiguration.swift; sourceTree = "<group>"; };
|
||||
C33FDAB1255A580000E217F9 /* OWSStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSStorage.m; sourceTree = "<group>"; };
|
||||
C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSStorage+Subclass.h"; sourceTree = "<group>"; };
|
||||
C33FDABE255A580100E217F9 /* TSConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSConstants.m; sourceTree = "<group>"; };
|
||||
C33FDAC3255A580200E217F9 /* OWSDispatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDispatch.m; sourceTree = "<group>"; };
|
||||
C33FDADE255A580400E217F9 /* SwiftSingletons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftSingletons.swift; sourceTree = "<group>"; };
|
||||
C33FDAE0255A580400E217F9 /* ByteParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ByteParser.m; sourceTree = "<group>"; };
|
||||
C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackupFragment.h; sourceTree = "<group>"; };
|
||||
C33FDAEF255A580500E217F9 /* NSData+Image.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Image.m"; sourceTree = "<group>"; };
|
||||
C33FDAF1255A580500E217F9 /* ThumbnailService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailService.swift; sourceTree = "<group>"; };
|
||||
C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxiedContentDownloader.swift; sourceTree = "<group>"; };
|
||||
C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIMETypeUtil.h; sourceTree = "<group>"; };
|
||||
C33FDAFD255A580600E217F9 /* LRUCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LRUCache.swift; sourceTree = "<group>"; };
|
||||
C33FDAFE255A580600E217F9 /* OWSStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSStorage.h; sourceTree = "<group>"; };
|
||||
C33FDB01255A580700E217F9 /* AppReadiness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppReadiness.h; sourceTree = "<group>"; };
|
||||
C33FDB07255A580700E217F9 /* OWSBackupFragment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackupFragment.m; sourceTree = "<group>"; };
|
||||
C33FDB12255A580800E217F9 /* NSString+SSK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SSK.h"; sourceTree = "<group>"; };
|
||||
C33FDB14255A580800E217F9 /* OWSMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMath.h; sourceTree = "<group>"; };
|
||||
C33FDB17255A580800E217F9 /* FunctionalUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FunctionalUtil.m; sourceTree = "<group>"; };
|
||||
C33FDB1C255A580900E217F9 /* UIImage+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+OWS.h"; sourceTree = "<group>"; };
|
||||
C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSDatabaseSecondaryIndexes.m; sourceTree = "<group>"; };
|
||||
C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSMediaUtils.swift; sourceTree = "<group>"; };
|
||||
C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSDatabaseSecondaryIndexes.h; sourceTree = "<group>"; };
|
||||
C33FDB29255A580A00E217F9 /* NSData+Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Image.h"; sourceTree = "<group>"; };
|
||||
C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSDatabaseView.h; sourceTree = "<group>"; };
|
||||
C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosedGroupPoller.swift; sourceTree = "<group>"; };
|
||||
C33FDB36255A580B00E217F9 /* Storage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
|
||||
C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackgroundTask.h; sourceTree = "<group>"; };
|
||||
C33FDB3A255A580B00E217F9 /* Poller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Poller.swift; sourceTree = "<group>"; };
|
||||
C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+OWS.h"; sourceTree = "<group>"; };
|
||||
C33FDB3F255A580C00E217F9 /* String+SSK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+SSK.swift"; sourceTree = "<group>"; };
|
||||
C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalIOSProto.swift; sourceTree = "<group>"; };
|
||||
C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIMETypeUtil.m; sourceTree = "<group>"; };
|
||||
C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "YapDatabaseConnection+OWS.m"; sourceTree = "<group>"; };
|
||||
C33FDB45255A580C00E217F9 /* NSString+SSK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SSK.m"; sourceTree = "<group>"; };
|
||||
C33FDB46255A580C00E217F9 /* TSDatabaseView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSDatabaseView.m; sourceTree = "<group>"; };
|
||||
C33FDB49255A580C00E217F9 /* WeakTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakTimer.swift; sourceTree = "<group>"; };
|
||||
C33FDB4C255A580D00E217F9 /* AppVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppVersion.h; sourceTree = "<group>"; };
|
||||
C33FDB51255A580D00E217F9 /* NSUserDefaults+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSUserDefaults+OWS.h"; sourceTree = "<group>"; };
|
||||
C33FDB54255A580D00E217F9 /* DataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataSource.h; sourceTree = "<group>"; };
|
||||
C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "YapDatabaseTransaction+OWS.m"; sourceTree = "<group>"; };
|
||||
C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YapDatabaseConnection+OWS.h"; sourceTree = "<group>"; };
|
||||
C33FDB68255A580F00E217F9 /* ContentProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentProxy.swift; sourceTree = "<group>"; };
|
||||
C33FDB69255A580F00E217F9 /* FeatureFlags.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureFlags.swift; sourceTree = "<group>"; };
|
||||
C33FDB6B255A580F00E217F9 /* SNUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SNUserDefaults.swift; sourceTree = "<group>"; };
|
||||
|
@ -1272,7 +1228,6 @@
|
|||
C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKGroupUtilities.m; sourceTree = "<group>"; };
|
||||
C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLSessionDataTask+StatusCode.h"; sourceTree = "<group>"; };
|
||||
C33FDBF9255A581C00E217F9 /* OWSError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSError.h; sourceTree = "<group>"; };
|
||||
C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSPrimaryStorage.m; sourceTree = "<group>"; };
|
||||
C33FDC03255A581D00E217F9 /* ByteParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByteParser.h; sourceTree = "<group>"; };
|
||||
C33FDC0B255A581D00E217F9 /* OWSError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSError.m; sourceTree = "<group>"; };
|
||||
C33FDC12255A581E00E217F9 /* TSConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSConstants.h; sourceTree = "<group>"; };
|
||||
|
@ -1426,7 +1381,6 @@
|
|||
C3ADC66026426688005F1414 /* ShareVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareVC.swift; sourceTree = "<group>"; };
|
||||
C3AECBEA24EF5244005743DE /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
C3BBE0752554CDA60050F1E3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
|
||||
C3BBE07F2554CDD70050F1E3 /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
|
||||
C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FixedWidthInteger+BigEndian.swift"; sourceTree = "<group>"; };
|
||||
C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SessionSnodeKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C3C2A5A1255385C100C340D1 /* SessionSnodeKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SessionSnodeKit.h; sourceTree = "<group>"; };
|
||||
|
@ -1472,7 +1426,6 @@
|
|||
C3CA3ABD255CDB0D00F4C6D4 /* portuguese.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = portuguese.txt; sourceTree = "<group>"; };
|
||||
C3CA3AC7255CDB2900F4C6D4 /* spanish.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = spanish.txt; sourceTree = "<group>"; };
|
||||
C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundPoller.swift; sourceTree = "<group>"; };
|
||||
C3D9E41E25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSPrimaryStorageProtocol.swift; sourceTree = "<group>"; };
|
||||
C3D9E43025676D3D0040E4F3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
|
||||
C3DA9C0625AE7396008F7C7E /* ConfigurationMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationMessage.swift; sourceTree = "<group>"; };
|
||||
C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCopyableLabel.swift; sourceTree = "<group>"; };
|
||||
|
@ -1487,7 +1440,6 @@
|
|||
C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoopNotificationsManager.swift; sourceTree = "<group>"; };
|
||||
C3F0A5B2255C915C007BE2A3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
C3F0A5EB255C970D007BE2A3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
|
||||
C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Shared.swift"; sourceTree = "<group>"; };
|
||||
C5060C3B36A848B71CCE4685 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionUtilitiesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionUtilitiesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C88965DE4F4EC4FC919BEC4E /* Pods-SessionUIKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUIKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUIKit/Pods-SessionUIKit.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
C98441E849C3CA7FE8220D33 /* Pods-SessionNotificationServiceExtension.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionNotificationServiceExtension.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SessionNotificationServiceExtension/Pods-SessionNotificationServiceExtension.app store release.xcconfig"; sourceTree = "<group>"; };
|
||||
|
@ -1852,7 +1804,6 @@
|
|||
4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */,
|
||||
34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */,
|
||||
34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */,
|
||||
4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */,
|
||||
FD848B9728422F1A000E298B /* Date+Utilities.swift */,
|
||||
FDD2506D283711D600198BDA /* DifferenceKit+Utilities.swift */,
|
||||
4C21D5D5223A9DC500EF8A77 /* UIAlerts+iOS9.m */,
|
||||
|
@ -2081,11 +2032,7 @@
|
|||
FD28A4F527EAD44C00FF65E7 /* GRDBStorage.swift */,
|
||||
C33FDBAB255A581500E217F9 /* OWSFileSystem.h */,
|
||||
C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */,
|
||||
C3D9E41E25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift */,
|
||||
C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */,
|
||||
C33FDB36255A580B00E217F9 /* Storage.swift */,
|
||||
C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */,
|
||||
C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */,
|
||||
);
|
||||
path = Database;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2385,19 +2332,6 @@
|
|||
FD17D79427F3E03300122BE0 /* Migrations */,
|
||||
FD09796C27FA6C8B00936362 /* Models */,
|
||||
B8F5F56425EC8453003BF8D4 /* Notification+Contacts.swift */,
|
||||
C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */,
|
||||
C33FDB07255A580700E217F9 /* OWSBackupFragment.m */,
|
||||
C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */,
|
||||
C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */,
|
||||
C33FDAFE255A580600E217F9 /* OWSStorage.h */,
|
||||
C33FDAB1255A580000E217F9 /* OWSStorage.m */,
|
||||
C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */,
|
||||
B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */,
|
||||
C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */,
|
||||
C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */,
|
||||
C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */,
|
||||
C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */,
|
||||
C33FDB46255A580C00E217F9 /* TSDatabaseView.m */,
|
||||
);
|
||||
path = Database;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2475,7 +2409,6 @@
|
|||
children = (
|
||||
C33FD9B7255A54A300E217F9 /* Meta */,
|
||||
C3F0A5EB255C970D007BE2A3 /* Configuration.swift */,
|
||||
C38BBA0E255E32440041B9A3 /* Database */,
|
||||
C36096ED25AD20FD008B62B2 /* Media Viewing & Editing */,
|
||||
C38BBA0D255E321C0041B9A3 /* Messaging */,
|
||||
C36096EF25AD2268008B62B2 /* Profile Pictures */,
|
||||
|
@ -2704,13 +2637,6 @@
|
|||
path = Notifications;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C379DCE82567330E0002D4EB /* Migrations */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
path = Migrations;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C379DCE9256733390002D4EB /* Image Editing */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2777,15 +2703,6 @@
|
|||
path = Messaging;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C38BBA0E255E32440041B9A3 /* Database */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C379DCE82567330E0002D4EB /* Migrations */,
|
||||
C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */,
|
||||
);
|
||||
path = Database;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C3A721332558BDDF0043A11F /* Open Groups */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2836,10 +2753,6 @@
|
|||
C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */,
|
||||
C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */,
|
||||
C3ECBF7A257056B700EA7FCE /* Threading.swift */,
|
||||
C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */,
|
||||
C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */,
|
||||
C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */,
|
||||
C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */,
|
||||
);
|
||||
path = Utilities;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2916,7 +2829,6 @@
|
|||
children = (
|
||||
C3C2A7802553AA6300C340D1 /* Protos */,
|
||||
C3C2A70A25539DF900C340D1 /* Meta */,
|
||||
C3BBE07F2554CDD70050F1E3 /* Storage.swift */,
|
||||
C32C5BCB256DC818003C73A2 /* Database */,
|
||||
C300A5BB2554AFFB00555489 /* Messages */,
|
||||
C300A5F02554B08500555489 /* Sending & Receiving */,
|
||||
|
@ -3497,7 +3409,6 @@
|
|||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C3D9E3FA25676BCE0040E4F3 /* TSYapDatabaseObject.h in Headers */,
|
||||
C3D9E3A4256763DE0040E4F3 /* AppContext.h in Headers */,
|
||||
C3D9E38A256760390040E4F3 /* OWSFileSystem.h in Headers */,
|
||||
C352A3B72557B6ED00338F3E /* TSRequest.h in Headers */,
|
||||
|
@ -3520,21 +3431,13 @@
|
|||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C32C5EE5256DF506003C73A2 /* YapDatabaseConnection+OWS.h in Headers */,
|
||||
C3C2A6F425539DE700C340D1 /* SessionMessagingKit.h in Headers */,
|
||||
C32C5C46256DCBB2003C73A2 /* AppReadiness.h in Headers */,
|
||||
B8856CB1256F0F47001CE70E /* OWSBackupFragment.h in Headers */,
|
||||
C3A3A12B256E1AD5004D228D /* TSDatabaseSecondaryIndexes.h in Headers */,
|
||||
C32C5FC4256E0209003C73A2 /* OWSBackgroundTask.h in Headers */,
|
||||
C32C5EF7256DF567003C73A2 /* TSDatabaseView.h in Headers */,
|
||||
B8856ED7256F1EB4001CE70E /* OWSPreferences.h in Headers */,
|
||||
C32A026C25A801AF000ED5D4 /* NSData+messagePadding.h in Headers */,
|
||||
B8856D72256F1421001CE70E /* OWSWindowManager.h in Headers */,
|
||||
B8856CF7256F105E001CE70E /* OWSAudioPlayer.h in Headers */,
|
||||
C32C5E7E256DE023003C73A2 /* YapDatabaseTransaction+OWS.h in Headers */,
|
||||
C32C5EA0256DE0D6003C73A2 /* OWSPrimaryStorage.h in Headers */,
|
||||
B8856E33256F18D5001CE70E /* OWSStorage+Subclass.h in Headers */,
|
||||
C32C5E64256DDFD6003C73A2 /* OWSStorage.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -4295,7 +4198,6 @@
|
|||
C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */,
|
||||
C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */,
|
||||
C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */,
|
||||
C33FDC27255A581F00E217F9 /* YapDatabase+Promise.swift in Sources */,
|
||||
C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */,
|
||||
C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */,
|
||||
C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */,
|
||||
|
@ -4354,7 +4256,6 @@
|
|||
7B1D74AC27BDE7510030B423 /* Promise+Timeout.swift in Sources */,
|
||||
C3AABDDF2553ECF00042FF4C /* Array+Utilities.swift in Sources */,
|
||||
C32C5A47256DB8F0003C73A2 /* ECKeyPair+Hexadecimal.swift in Sources */,
|
||||
C3D9E41525676C320040E4F3 /* Storage.swift in Sources */,
|
||||
7B1D74B027C365960030B423 /* Timer+MainThread.swift in Sources */,
|
||||
C32C5D83256DD5B6003C73A2 /* SSKKeychainStorage.swift in Sources */,
|
||||
C3D9E39B256763C20040E4F3 /* AppContext.m in Sources */,
|
||||
|
@ -4393,7 +4294,6 @@
|
|||
C3C2AC2E2553CBEB00C340D1 /* String+Trimming.swift in Sources */,
|
||||
C32C5B48256DC211003C73A2 /* NSNotificationCenter+OWS.m in Sources */,
|
||||
FD17D7C727F5207C00122BE0 /* DatabaseMigrator+Utilities.swift in Sources */,
|
||||
C3D9E3C925676AF30040E4F3 /* TSYapDatabaseObject.m in Sources */,
|
||||
C352A3A62557B60D00338F3E /* TSRequest.m in Sources */,
|
||||
FD848B9328420164000E298B /* UnicodeScalar+Utilities.swift in Sources */,
|
||||
FD09796B27F6C67500936362 /* Failable.swift in Sources */,
|
||||
|
@ -4415,7 +4315,6 @@
|
|||
B8BC00C0257D90E30032E807 /* General.swift in Sources */,
|
||||
FD17D7A127F40D2500122BE0 /* GRDBStorage.swift in Sources */,
|
||||
C32C5A24256DB7DB003C73A2 /* SNUserDefaults.swift in Sources */,
|
||||
C3D9E41F25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift in Sources */,
|
||||
C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */,
|
||||
B8856D7B256F14F4001CE70E /* UIView+OWS.m in Sources */,
|
||||
FD17D7B027F4225C00122BE0 /* Set+Utilities.swift in Sources */,
|
||||
|
@ -4478,11 +4377,9 @@
|
|||
FDF0B7472804F0CE004C14C5 /* DisappearingMessagesJob.swift in Sources */,
|
||||
B8856D1A256F114D001CE70E /* ProximityMonitoringManager.swift in Sources */,
|
||||
C3D9E52725677DF20040E4F3 /* ThumbnailService.swift in Sources */,
|
||||
C32C5E75256DE020003C73A2 /* YapDatabaseTransaction+OWS.m in Sources */,
|
||||
FDF0B73C27FFD3D6004C14C5 /* LinkPreview.swift in Sources */,
|
||||
FD09797527FAB64300936362 /* ProfileManager.swift in Sources */,
|
||||
FDA8EAFE280E8B78002B68E5 /* FailedMessageSendsJob.swift in Sources */,
|
||||
C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */,
|
||||
C3DB66AC260ACA42001EFC55 /* OpenGroupManagerV2.swift in Sources */,
|
||||
C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */,
|
||||
FD09797F27FCFBFF00936362 /* OWSAES256Key+Utilities.swift in Sources */,
|
||||
|
@ -4513,18 +4410,14 @@
|
|||
C3C2A7712553A41E00C340D1 /* ControlMessage.swift in Sources */,
|
||||
C32C5D19256DD493003C73A2 /* LinkPreviewDraft.swift in Sources */,
|
||||
FD3C907527E83AC200CD579F /* OpenGroupServerIdLookup.swift in Sources */,
|
||||
C32C5CF0256DD3E4003C73A2 /* Storage+Shared.swift in Sources */,
|
||||
C300A5BD2554B00D00555489 /* ReadReceipt.swift in Sources */,
|
||||
FDF0B7582807F368004C14C5 /* MessageReceiverError.swift in Sources */,
|
||||
C32C5E5B256DDF45003C73A2 /* OWSStorage.m in Sources */,
|
||||
C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */,
|
||||
FD6A7A692818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift in Sources */,
|
||||
C3DA9C0725AE7396008F7C7E /* ConfigurationMessage.swift in Sources */,
|
||||
B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */,
|
||||
FD5D200F27AA2B6000FEA984 /* MessageRequestResponse.swift in Sources */,
|
||||
FD09798D27FD1D8900936362 /* DisappearingMessageConfiguration.swift in Sources */,
|
||||
FDF0B75A2807F3A3004C14C5 /* MessageSenderError.swift in Sources */,
|
||||
C32C5EDC256DF501003C73A2 /* YapDatabaseConnection+OWS.m in Sources */,
|
||||
C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */,
|
||||
B8856D69256F141F001CE70E /* OWSWindowManager.m in Sources */,
|
||||
C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */,
|
||||
|
@ -4535,12 +4428,10 @@
|
|||
C34A977425A3E34A00852C71 /* ClosedGroupControlMessage.swift in Sources */,
|
||||
FD09799527FE7B8E00936362 /* Interaction.swift in Sources */,
|
||||
B88FA7B826045D100049422F /* OpenGroupAPIV2.swift in Sources */,
|
||||
C32C5E97256DE0CB003C73A2 /* OWSPrimaryStorage.m in Sources */,
|
||||
C3A71D1F25589AC30043A11F /* WebSocketResources.pb.swift in Sources */,
|
||||
FDF0B74B28061F7A004C14C5 /* InteractionAttachment.swift in Sources */,
|
||||
B8F5F56525EC8453003BF8D4 /* Notification+Contacts.swift in Sources */,
|
||||
FD09796E27FA6D0000936362 /* Contact.swift in Sources */,
|
||||
C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */,
|
||||
C38D5E8D2575011E00B6A65C /* MessageSender+ClosedGroups.swift in Sources */,
|
||||
C3DB6695260AC923001EFC55 /* OpenGroupV2.swift in Sources */,
|
||||
C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */,
|
||||
|
@ -4553,14 +4444,12 @@
|
|||
C3C2A75F2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift in Sources */,
|
||||
C32C5FBB256E0206003C73A2 /* OWSBackgroundTask.m in Sources */,
|
||||
FD848B8D283E0B26000E298B /* MessageInputTypes.swift in Sources */,
|
||||
B8856CA8256F0F42001CE70E /* OWSBackupFragment.m in Sources */,
|
||||
C32C5C3D256DCBAF003C73A2 /* AppReadiness.m in Sources */,
|
||||
B87EF17126367CF800124B3C /* FileServerAPIV2.swift in Sources */,
|
||||
FD09799B27FFC82D00936362 /* Quote.swift in Sources */,
|
||||
C3C2A74425539EB700C340D1 /* Message.swift in Sources */,
|
||||
FD09798527FD1A6500936362 /* ClosedGroupKeyPair.swift in Sources */,
|
||||
C32C5DBF256DD743003C73A2 /* ClosedGroupPoller.swift in Sources */,
|
||||
C32C5EEE256DF54E003C73A2 /* TSDatabaseView.m in Sources */,
|
||||
C352A35B2557824E00338F3E /* AttachmentUploadJob.swift in Sources */,
|
||||
FD09797027FA6FF300936362 /* Profile.swift in Sources */,
|
||||
FD09798B27FD1CFE00936362 /* Capability.swift in Sources */,
|
||||
|
@ -4657,7 +4546,6 @@
|
|||
B8F5F71A25F1B35C003BF8D4 /* MediaPlaceholderView.swift in Sources */,
|
||||
4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */,
|
||||
C331FFF32558FF0300070591 /* PathStatusView.swift in Sources */,
|
||||
4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */,
|
||||
B848A4C5269EAAA200617031 /* UserDetailsSheet.swift in Sources */,
|
||||
34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */,
|
||||
B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */,
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#import <SignalCoreKit/NSDate+OWS.h>
|
||||
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
|
||||
#import <SignalUtilitiesKit/UIUtil.h>
|
||||
#import <SessionMessagingKit/OWSPrimaryStorage.h>
|
||||
|
||||
@import ContactsUI;
|
||||
@import PromiseKit;
|
||||
|
@ -27,8 +26,6 @@ CGFloat kIconViewLength = 24;
|
|||
@property (nonatomic) BOOL isNoteToSelf;
|
||||
@property (nonatomic) BOOL isClosedGroup;
|
||||
@property (nonatomic) BOOL isOpenGroup;
|
||||
@property (nonatomic) YapDatabaseConnection *uiDatabaseConnection;
|
||||
@property (nonatomic, readonly) YapDatabaseConnection *editingDatabaseConnection;
|
||||
@property (nonatomic) NSArray<NSNumber *> *disappearingMessagesDurations;
|
||||
|
||||
@property (nonatomic) BOOL originalIsDisappearingMessagesEnabled;
|
||||
|
@ -106,11 +103,6 @@ CGFloat kIconViewLength = 24;
|
|||
object:nil];
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)editingDatabaseConnection
|
||||
{
|
||||
return [OWSPrimaryStorage sharedManager].dbReadWriteConnection;
|
||||
}
|
||||
|
||||
- (void)configureWithThreadId:(NSString *)threadId threadName:(nullable NSString *)threadName isClosedGroup:(BOOL)isClosedGroup isOpenGroup:(BOOL)isOpenGroup isNoteToSelf:(BOOL)isNoteToSelf {
|
||||
self.threadId = threadId;
|
||||
self.threadName = threadName;
|
||||
|
|
|
@ -236,14 +236,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
private func verifyDBKeysAvailableBeforeBackgroundLaunch() {
|
||||
guard UIApplication.shared.applicationState == .background else { return }
|
||||
|
||||
// Ensure both databases are accessible (as long as we are supporting the YDB migration
|
||||
// we should keep this check)
|
||||
let databasePasswordAccessible: Bool = (
|
||||
GRDBStorage.isDatabasePasswordAccessible && // GRDB password access
|
||||
OWSStorage.isDatabasePasswordAccessible() // YapDatabase password access
|
||||
)
|
||||
|
||||
guard !databasePasswordAccessible else { return } // All good
|
||||
guard !GRDBStorage.isDatabasePasswordAccessible else { return } // All good
|
||||
|
||||
Logger.info("Exiting because we are in the background and the database password is not accessible.")
|
||||
|
||||
|
|
|
@ -57,9 +57,8 @@ public struct SessionApp {
|
|||
Logger.error("")
|
||||
DDLog.flushLog()
|
||||
|
||||
OWSStorage.resetAllStorage()
|
||||
GRDBStorage.resetAllStorage()
|
||||
ProfileManager.resetProfileStorage()
|
||||
Environment.shared.preferences.clear()
|
||||
AppEnvironment.shared.notificationPresenter.clearAllNotifications()
|
||||
|
||||
onReset?()
|
||||
|
|
|
@ -118,12 +118,6 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
|
|||
SwiftSingletons.register(self)
|
||||
}
|
||||
|
||||
// MARK: - Dependencies
|
||||
|
||||
var preferences: OWSPreferences {
|
||||
return Environment.shared.preferences
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
@objc
|
||||
|
@ -380,10 +374,6 @@ class NotificationActionHandler {
|
|||
return AppEnvironment.shared.notificationPresenter
|
||||
}
|
||||
|
||||
var dbConnection: YapDatabaseConnection {
|
||||
return OWSPrimaryStorage.shared().dbReadWriteConnection
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
func markAsRead(userInfo: [AnyHashable: Any]) throws -> Promise<Void> {
|
||||
|
|
|
@ -1,243 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import PromiseKit
|
||||
|
||||
@objc
|
||||
class AppUpdateNag: NSObject {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
@objc(sharedInstance)
|
||||
public static let shared: AppUpdateNag = {
|
||||
let versionService = AppStoreVersionService()
|
||||
let nagManager = AppUpdateNag(versionService: versionService)
|
||||
return nagManager
|
||||
}()
|
||||
|
||||
@objc
|
||||
public func showAppUpgradeNagIfNecessary() {
|
||||
return
|
||||
|
||||
/*
|
||||
guard let currentVersion = self.currentVersion else {
|
||||
owsFailDebug("currentVersion was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
guard let bundleIdentifier = self.bundleIdentifier else {
|
||||
owsFailDebug("bundleIdentifier was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
guard let lookupURL = lookupURL(bundleIdentifier: bundleIdentifier) else {
|
||||
owsFailDebug("appStoreURL was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
firstly {
|
||||
self.versionService.fetchLatestVersion(lookupURL: lookupURL)
|
||||
}.done { appStoreRecord in
|
||||
guard appStoreRecord.version.compare(currentVersion, options: .numeric) == ComparisonResult.orderedDescending else {
|
||||
Logger.debug("remote version: \(appStoreRecord) is not newer than currentVersion: \(currentVersion)")
|
||||
return
|
||||
}
|
||||
|
||||
Logger.info("new version available: \(appStoreRecord)")
|
||||
self.showUpdateNagIfEnoughTimeHasPassed(appStoreRecord: appStoreRecord)
|
||||
}.catch { error in
|
||||
Logger.error("failed with error: \(error)")
|
||||
}.retainUntilComplete()
|
||||
*/
|
||||
}
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
let kUpgradeNagCollection = "TSStorageManagerAppUpgradeNagCollection"
|
||||
let kLastNagDateKey = "TSStorageManagerAppUpgradeNagDate"
|
||||
let kFirstHeardOfNewVersionDateKey = "TSStorageManagerAppUpgradeFirstHeardOfNewVersionDate"
|
||||
|
||||
var dbConnection: YapDatabaseConnection {
|
||||
return OWSPrimaryStorage.shared().dbReadWriteConnection
|
||||
}
|
||||
|
||||
// MARK: Bundle accessors
|
||||
|
||||
var bundle: Bundle {
|
||||
return Bundle.main
|
||||
}
|
||||
|
||||
var currentVersion: String? {
|
||||
return bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
|
||||
}
|
||||
|
||||
var bundleIdentifier: String? {
|
||||
return bundle.bundleIdentifier
|
||||
}
|
||||
|
||||
func lookupURL(bundleIdentifier: String) -> URL? {
|
||||
return URL(string: "https://itunes.apple.com/lookup?bundleId=\(bundleIdentifier)")
|
||||
}
|
||||
|
||||
let versionService: AppStoreVersionService
|
||||
|
||||
required init(versionService: AppStoreVersionService) {
|
||||
self.versionService = versionService
|
||||
super.init()
|
||||
|
||||
SwiftSingletons.register(self)
|
||||
}
|
||||
|
||||
func showUpdateNagIfEnoughTimeHasPassed(appStoreRecord: AppStoreRecord) {
|
||||
guard let firstHeardOfNewVersionDate = self.firstHeardOfNewVersionDate else {
|
||||
self.setFirstHeardOfNewVersionDate(Date())
|
||||
return
|
||||
}
|
||||
|
||||
let intervalBeforeNag = 7 * kDayInterval
|
||||
guard Date() > Date.init(timeInterval: intervalBeforeNag, since: firstHeardOfNewVersionDate) else {
|
||||
Logger.info("firstHeardOfNewVersionDate: \(firstHeardOfNewVersionDate) not nagging for new release yet.")
|
||||
return
|
||||
}
|
||||
|
||||
if let lastNagDate = self.lastNagDate {
|
||||
let intervalBetweenNags = 14 * kDayInterval
|
||||
guard Date() > Date.init(timeInterval: intervalBetweenNags, since: lastNagDate) else {
|
||||
Logger.info("lastNagDate: \(lastNagDate) not nagging again so soon.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Only show nag if we are "at rest" in the home view or registration view without any
|
||||
// alerts or dialogs showing.
|
||||
guard UIApplication.shared.frontmostViewController != nil else {
|
||||
owsFailDebug("frontmostViewController was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
switch frontmostViewController {
|
||||
case is OnboardingSplashViewController:
|
||||
self.setLastNagDate(Date())
|
||||
self.clearFirstHeardOfNewVersionDate()
|
||||
presentUpgradeNag(appStoreRecord: appStoreRecord)
|
||||
default:
|
||||
Logger.debug("not presenting alert due to frontmostViewController: \(frontmostViewController)")
|
||||
break
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
func presentUpgradeNag(appStoreRecord: AppStoreRecord) {
|
||||
let title = NSLocalizedString("APP_UPDATE_NAG_ALERT_TITLE", comment: "Title for the 'new app version available' alert.")
|
||||
|
||||
let bodyFormat = NSLocalizedString("APP_UPDATE_NAG_ALERT_MESSAGE_FORMAT", comment: "Message format for the 'new app version available' alert. Embeds: {{The latest app version number}}")
|
||||
let bodyText = String(format: bodyFormat, appStoreRecord.version)
|
||||
let updateButtonText = NSLocalizedString("APP_UPDATE_NAG_ALERT_UPDATE_BUTTON", comment: "Label for the 'update' button in the 'new app version available' alert.")
|
||||
let dismissButtonText = NSLocalizedString("APP_UPDATE_NAG_ALERT_DISMISS_BUTTON", comment: "Label for the 'dismiss' button in the 'new app version available' alert.")
|
||||
|
||||
let alert = UIAlertController(title: title, message: bodyText, preferredStyle: .alert)
|
||||
|
||||
let updateAction = UIAlertAction(title: updateButtonText, style: .default) { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.showAppStore(appStoreURL: appStoreRecord.appStoreURL)
|
||||
}
|
||||
|
||||
alert.addAction(updateAction)
|
||||
alert.addAction(UIAlertAction(title: dismissButtonText, style: .cancel, handler: nil))
|
||||
|
||||
OWSAlerts.showAlert(alert)
|
||||
}
|
||||
|
||||
func showAppStore(appStoreURL: URL) {
|
||||
Logger.debug("")
|
||||
UIApplication.shared.openURL(appStoreURL)
|
||||
}
|
||||
|
||||
// MARK: Storage
|
||||
|
||||
var firstHeardOfNewVersionDate: Date? {
|
||||
return self.dbConnection.date(forKey: kFirstHeardOfNewVersionDateKey, inCollection: kUpgradeNagCollection)
|
||||
}
|
||||
|
||||
func setFirstHeardOfNewVersionDate(_ date: Date) {
|
||||
self.dbConnection.setDate(date, forKey: kFirstHeardOfNewVersionDateKey, inCollection: kUpgradeNagCollection)
|
||||
}
|
||||
|
||||
func clearFirstHeardOfNewVersionDate() {
|
||||
self.dbConnection.removeObject(forKey: kFirstHeardOfNewVersionDateKey, inCollection: kUpgradeNagCollection)
|
||||
}
|
||||
|
||||
var lastNagDate: Date? {
|
||||
return self.dbConnection.date(forKey: kLastNagDateKey, inCollection: kUpgradeNagCollection)
|
||||
}
|
||||
|
||||
func setLastNagDate(_ date: Date) {
|
||||
self.dbConnection.setDate(date, forKey: kLastNagDateKey, inCollection: kUpgradeNagCollection)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Parsing Structs
|
||||
|
||||
struct AppStoreLookupResultSet: Codable {
|
||||
let resultCount: UInt
|
||||
let results: [AppStoreRecord]
|
||||
}
|
||||
|
||||
struct AppStoreRecord: Codable {
|
||||
let appStoreURL: URL
|
||||
let version: String
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case appStoreURL = "trackViewUrl"
|
||||
case version
|
||||
}
|
||||
}
|
||||
|
||||
class AppStoreVersionService: NSObject {
|
||||
|
||||
// MARK:
|
||||
|
||||
func fetchLatestVersion(lookupURL: URL) -> Promise<AppStoreRecord> {
|
||||
Logger.debug("lookupURL:\(lookupURL)")
|
||||
|
||||
let (promise, resolver) = Promise<AppStoreRecord>.pending()
|
||||
|
||||
let task = URLSession.ephemeral.dataTask(with: lookupURL) { (data, _, error) in
|
||||
guard let data = data else {
|
||||
Logger.warn("data was unexpectedly nil")
|
||||
resolver.reject(OWSErrorMakeUnableToProcessServerResponseError())
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let decoder = JSONDecoder()
|
||||
let resultSet = try decoder.decode(AppStoreLookupResultSet.self, from: data)
|
||||
guard let appStoreRecord = resultSet.results.first else {
|
||||
Logger.warn("record was unexpectedly nil")
|
||||
resolver.reject(OWSErrorMakeUnableToProcessServerResponseError())
|
||||
return
|
||||
}
|
||||
|
||||
resolver.fulfill(appStoreRecord)
|
||||
} catch {
|
||||
resolver.reject(error)
|
||||
}
|
||||
}
|
||||
|
||||
task.resume()
|
||||
|
||||
return promise
|
||||
}
|
||||
}
|
||||
|
||||
extension URLSession {
|
||||
static var ephemeral: URLSession {
|
||||
return URLSession(configuration: .ephemeral)
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
import Foundation
|
||||
import AVKit
|
||||
import GRDB
|
||||
import YapDatabase
|
||||
import Curve25519Kit
|
||||
import SessionUtilitiesKit
|
||||
import SessionSnodeKit
|
||||
|
@ -278,38 +279,49 @@ enum _003_YDBToGRDBMigration: Migration {
|
|||
|
||||
// Note: The 'int(forKey:inCollection:)' defaults to `0` which is an incorrect value
|
||||
// for the notification sound so catch it and default
|
||||
let globalNotificationSoundValue: Int32 = transaction.int(
|
||||
forKey: SMKLegacy.soundsGlobalNotificationKey,
|
||||
inCollection: SMKLegacy.soundsStorageNotificationCollection
|
||||
)
|
||||
legacyPreferences[SMKLegacy.soundsGlobalNotificationKey] = (globalNotificationSoundValue > 0 ?
|
||||
Int(globalNotificationSoundValue) :
|
||||
Preferences.Sound.defaultNotificationSound.rawValue
|
||||
)
|
||||
legacyPreferences[SMKLegacy.soundsGlobalNotificationKey] = (transaction
|
||||
.object(
|
||||
forKey: SMKLegacy.soundsGlobalNotificationKey,
|
||||
inCollection: SMKLegacy.soundsStorageNotificationCollection
|
||||
)
|
||||
.asType(NSNumber.self)?
|
||||
.intValue)
|
||||
.defaulting(to: Preferences.Sound.defaultNotificationSound.rawValue)
|
||||
|
||||
legacyPreferences[SMKLegacy.readReceiptManagerAreReadReceiptsEnabled] = transaction.bool(
|
||||
forKey: SMKLegacy.readReceiptManagerAreReadReceiptsEnabled,
|
||||
inCollection: SMKLegacy.readReceiptManagerCollection,
|
||||
defaultValue: false
|
||||
)
|
||||
legacyPreferences[SMKLegacy.readReceiptManagerAreReadReceiptsEnabled] = (transaction
|
||||
.object(
|
||||
forKey: SMKLegacy.readReceiptManagerAreReadReceiptsEnabled,
|
||||
inCollection: SMKLegacy.readReceiptManagerCollection
|
||||
)
|
||||
.asType(NSNumber.self)?
|
||||
.boolValue)
|
||||
.defaulting(to: false)
|
||||
|
||||
legacyPreferences[SMKLegacy.typingIndicatorsEnabledKey] = transaction.bool(
|
||||
forKey: SMKLegacy.typingIndicatorsEnabledKey,
|
||||
inCollection: SMKLegacy.typingIndicatorsCollection,
|
||||
defaultValue: false
|
||||
)
|
||||
legacyPreferences[SMKLegacy.typingIndicatorsEnabledKey] = (transaction
|
||||
.object(
|
||||
forKey: SMKLegacy.typingIndicatorsEnabledKey,
|
||||
inCollection: SMKLegacy.typingIndicatorsCollection
|
||||
)
|
||||
.asType(NSNumber.self)?
|
||||
.boolValue)
|
||||
.defaulting(to: false)
|
||||
|
||||
legacyPreferences[SMKLegacy.screenLockIsScreenLockEnabledKey] = transaction.bool(
|
||||
forKey: SMKLegacy.screenLockIsScreenLockEnabledKey,
|
||||
inCollection: SMKLegacy.screenLockCollection,
|
||||
defaultValue: false
|
||||
)
|
||||
legacyPreferences[SMKLegacy.screenLockIsScreenLockEnabledKey] = (transaction
|
||||
.object(
|
||||
forKey: SMKLegacy.screenLockIsScreenLockEnabledKey,
|
||||
inCollection: SMKLegacy.screenLockCollection
|
||||
)
|
||||
.asType(NSNumber.self)?
|
||||
.boolValue)
|
||||
.defaulting(to: false)
|
||||
|
||||
legacyPreferences[SMKLegacy.screenLockScreenLockTimeoutSecondsKey] = transaction.double(
|
||||
forKey: SMKLegacy.screenLockScreenLockTimeoutSecondsKey,
|
||||
inCollection: SMKLegacy.screenLockCollection,
|
||||
defaultValue: (15 * 60)
|
||||
)
|
||||
legacyPreferences[SMKLegacy.screenLockScreenLockTimeoutSecondsKey] = (transaction
|
||||
.object(
|
||||
forKey: SMKLegacy.screenLockScreenLockTimeoutSecondsKey,
|
||||
inCollection: SMKLegacy.screenLockCollection)
|
||||
.asType(NSNumber.self)?
|
||||
.doubleValue)
|
||||
.defaulting(to: (15 * 60))
|
||||
GRDBStorage.shared.update(progress: 0.23, for: self, in: target)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import SessionUtilitiesKit
|
||||
|
||||
// FIXME: Remove these extensions once the OWSConversationSettingsViewModel is refactored to swift and uses proper database observation
|
||||
public extension Notification.Name {
|
||||
|
||||
static let otherUsersProfileDidChange = Notification.Name("otherUsersProfileDidChange")
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SessionUtilitiesKit/TSYapDatabaseObject.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// We store metadata for known backup fragments (i.e. CloudKit record) in
|
||||
// the database. We might learn about them from:
|
||||
//
|
||||
// * Past backup exports.
|
||||
// * An import downloading and parsing the manifest of the last complete backup.
|
||||
//
|
||||
// Storing this data in the database provides continuity.
|
||||
//
|
||||
// * Backup exports can reuse fragments from previous Backup exports even if they
|
||||
// don't complete (i.e. backup export resume).
|
||||
// * Backup exports can reuse fragments from the backup import, if any.
|
||||
@interface OWSBackupFragment : TSYapDatabaseObject
|
||||
|
||||
@property (nonatomic) NSString *recordName;
|
||||
|
||||
@property (nonatomic) NSData *encryptionKey;
|
||||
|
||||
// This property is only set for certain types of manifest item,
|
||||
// namely attachments where we need to know where the attachment's
|
||||
// file should reside relative to the attachments folder.
|
||||
@property (nonatomic, nullable) NSString *relativeFilePath;
|
||||
|
||||
// This property is only set for attachments.
|
||||
@property (nonatomic, nullable) NSString *attachmentId;
|
||||
|
||||
// This property is only set if the manifest item is downloaded.
|
||||
@property (nonatomic, nullable) NSString *downloadFilePath;
|
||||
|
||||
// This property is only set if the manifest item is compressed.
|
||||
@property (nonatomic, nullable) NSNumber *uncompressedDataLength;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,13 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSBackupFragment.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation OWSBackupFragment
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,51 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SessionMessagingKit/OWSStorage.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern NSString *const OWSUIDatabaseConnectionWillUpdateNotification;
|
||||
extern NSString *const OWSUIDatabaseConnectionDidUpdateNotification;
|
||||
extern NSString *const OWSUIDatabaseConnectionWillUpdateExternallyNotification;
|
||||
extern NSString *const OWSUIDatabaseConnectionDidUpdateExternallyNotification;
|
||||
extern NSString *const OWSUIDatabaseConnectionNotificationsKey;
|
||||
|
||||
@interface OWSPrimaryStorage : OWSStorage
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initStorage;
|
||||
|
||||
+ (instancetype)sharedManager NS_SWIFT_NAME(shared());
|
||||
|
||||
@property (nonatomic, readonly) YapDatabaseConnection *uiDatabaseConnection;
|
||||
@property (nonatomic, readonly) YapDatabaseConnection *dbReadConnection;
|
||||
@property (nonatomic, readonly) YapDatabaseConnection *dbReadWriteConnection;
|
||||
|
||||
- (void)updateUIDatabaseConnectionToLatest;
|
||||
|
||||
+ (YapDatabaseConnection *)dbReadConnection;
|
||||
+ (YapDatabaseConnection *)dbReadWriteConnection;
|
||||
|
||||
+ (nullable NSError *)migrateToSharedData;
|
||||
|
||||
+ (NSString *)databaseFilePath;
|
||||
|
||||
+ (NSString *)legacyDatabaseFilePath;
|
||||
+ (NSString *)legacyDatabaseFilePath_SHM;
|
||||
+ (NSString *)legacyDatabaseFilePath_WAL;
|
||||
+ (NSString *)sharedDataDatabaseFilePath;
|
||||
+ (NSString *)sharedDataDatabaseFilePath_SHM;
|
||||
+ (NSString *)sharedDataDatabaseFilePath_WAL;
|
||||
|
||||
+ (void)protectFiles;
|
||||
|
||||
#pragma mark - Misc.
|
||||
|
||||
- (void)touchDbAsync;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,382 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSPrimaryStorage.h"
|
||||
#import "AppContext.h"
|
||||
#import "OWSFileSystem.h"
|
||||
#import <SessionUtilitiesKit/SessionUtilitiesKit.h>
|
||||
#import "OWSStorage.h"
|
||||
#import "OWSStorage+Subclass.h"
|
||||
#import "TSDatabaseSecondaryIndexes.h"
|
||||
#import "TSDatabaseView.h"
|
||||
#import <SessionMessagingKit/SessionMessagingKit-Swift.h>
|
||||
#import <YapDatabase/YapDatabaseConnectionPool.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSString *const OWSUIDatabaseConnectionWillUpdateNotification = @"OWSUIDatabaseConnectionWillUpdateNotification";
|
||||
NSString *const OWSUIDatabaseConnectionDidUpdateNotification = @"OWSUIDatabaseConnectionDidUpdateNotification";
|
||||
NSString *const OWSUIDatabaseConnectionWillUpdateExternallyNotification = @"OWSUIDatabaseConnectionWillUpdateExternallyNotification";
|
||||
NSString *const OWSUIDatabaseConnectionDidUpdateExternallyNotification = @"OWSUIDatabaseConnectionDidUpdateExternallyNotification";
|
||||
|
||||
NSString *const OWSUIDatabaseConnectionNotificationsKey = @"OWSUIDatabaseConnectionNotificationsKey";
|
||||
|
||||
void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage)
|
||||
{
|
||||
[[storage newDatabaseConnection] asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
for (NSString *extensionName in storage.registeredExtensionNames) {
|
||||
YapDatabaseViewTransaction *_Nullable viewTransaction = [transaction ext:extensionName];
|
||||
if (!viewTransaction) {
|
||||
[OWSStorage incrementVersionOfDatabaseExtension:extensionName];
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSPrimaryStorage ()
|
||||
|
||||
@property (atomic) BOOL areAsyncRegistrationsComplete;
|
||||
@property (atomic) BOOL areSyncRegistrationsComplete;
|
||||
@property (nonatomic, readonly) YapDatabaseConnectionPool *dbReadPool;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSPrimaryStorage
|
||||
|
||||
@synthesize uiDatabaseConnection = _uiDatabaseConnection;
|
||||
|
||||
+ (instancetype)sharedManager
|
||||
{
|
||||
return SSKEnvironment.shared.primaryStorage;
|
||||
}
|
||||
|
||||
- (instancetype)initStorage
|
||||
{
|
||||
self = [super initStorage];
|
||||
|
||||
if (self) {
|
||||
[self loadDatabase];
|
||||
|
||||
_dbReadPool = [[YapDatabaseConnectionPool alloc] initWithDatabase:self.database];
|
||||
_dbReadPool.connectionLimit = 10; // Increase max read connection limit. Default is 3.
|
||||
_dbReadWriteConnection = [self newDatabaseConnection];
|
||||
_uiDatabaseConnection = [self newDatabaseConnection];
|
||||
|
||||
// Increase object cache limit. Default is 250.
|
||||
_uiDatabaseConnection.objectCacheLimit = 500;
|
||||
[_uiDatabaseConnection beginLongLivedReadTransaction];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(yapDatabaseModified:)
|
||||
name:YapDatabaseModifiedNotification
|
||||
object:self.dbNotificationObject];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(yapDatabaseModifiedExternally:)
|
||||
name:YapDatabaseModifiedExternallyNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)yapDatabaseModifiedExternally:(NSNotification *)notification
|
||||
{
|
||||
// Notify observers we're about to update the database connection
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionWillUpdateExternallyNotification object:self.dbNotificationObject];
|
||||
|
||||
// Move uiDatabaseConnection to the latest commit.
|
||||
// Do so atomically, and fetch all the notifications for each commit we jump.
|
||||
NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction];
|
||||
|
||||
// Notify observers that the uiDatabaseConnection was updated
|
||||
NSDictionary *userInfo = @{ OWSUIDatabaseConnectionNotificationsKey: notifications };
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionDidUpdateExternallyNotification
|
||||
object:self.dbNotificationObject
|
||||
userInfo:userInfo];
|
||||
}
|
||||
|
||||
- (void)yapDatabaseModified:(NSNotification *)notification
|
||||
{
|
||||
[self updateUIDatabaseConnectionToLatest];
|
||||
}
|
||||
|
||||
- (void)updateUIDatabaseConnectionToLatest
|
||||
{
|
||||
// Notify observers we're about to update the database connection
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionWillUpdateNotification object:self.dbNotificationObject];
|
||||
|
||||
// Move uiDatabaseConnection to the latest commit.
|
||||
// Do so atomically, and fetch all the notifications for each commit we jump.
|
||||
NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction];
|
||||
|
||||
// Notify observers that the uiDatabaseConnection was updated
|
||||
NSDictionary *userInfo = @{ OWSUIDatabaseConnectionNotificationsKey: notifications };
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionDidUpdateNotification
|
||||
object:self.dbNotificationObject
|
||||
userInfo:userInfo];
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)uiDatabaseConnection
|
||||
{
|
||||
return _uiDatabaseConnection;
|
||||
}
|
||||
|
||||
- (void)resetStorage
|
||||
{
|
||||
_dbReadPool = nil;
|
||||
_uiDatabaseConnection = 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.
|
||||
|
||||
self.areSyncRegistrationsComplete = YES;
|
||||
}
|
||||
|
||||
- (void)runAsyncRegistrationsWithCompletion:(void (^_Nonnull)(void))completion
|
||||
{
|
||||
// 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];
|
||||
[TSDatabaseView asyncRegisterThreadDatabaseView:self];
|
||||
[self asyncRegisterExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex]
|
||||
withName:[TSDatabaseSecondaryIndexes registerTimeStampIndexExtensionName]];
|
||||
|
||||
[TSDatabaseView asyncRegisterUnreadMentionDatabaseView:self];
|
||||
[TSDatabaseView asyncRegisterThreadOutgoingMessagesDatabaseView:self];
|
||||
|
||||
[FullTextSearchFinder asyncRegisterDatabaseExtensionWithStorage:self];
|
||||
[TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:self];
|
||||
|
||||
[self.database
|
||||
flushExtensionRequestsWithCompletionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
|
||||
completionBlock:^{
|
||||
self.areAsyncRegistrationsComplete = YES;
|
||||
|
||||
completion();
|
||||
|
||||
[self verifyDatabaseViews];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)verifyDatabaseViews
|
||||
{
|
||||
VerifyRegistrationsForPrimaryStorage(self);
|
||||
}
|
||||
|
||||
+ (void)protectFiles
|
||||
{
|
||||
// Protect the entire new database directory.
|
||||
[OWSFileSystem protectFileOrFolderAtPath:self.sharedDataDatabaseDirPath];
|
||||
}
|
||||
|
||||
+ (NSString *)legacyDatabaseDirPath
|
||||
{
|
||||
return [OWSFileSystem appDocumentDirectoryPath];
|
||||
}
|
||||
|
||||
+ (NSString *)sharedDataDatabaseDirPath
|
||||
{
|
||||
NSString *databaseDirPath = [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"database"];
|
||||
|
||||
[OWSFileSystem ensureDirectoryExists:databaseDirPath];
|
||||
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.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename];
|
||||
}
|
||||
|
||||
+ (NSString *)sharedDataDatabaseFilePath_SHM
|
||||
{
|
||||
return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_SHM];
|
||||
}
|
||||
|
||||
+ (NSString *)sharedDataDatabaseFilePath_WAL
|
||||
{
|
||||
return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL];
|
||||
}
|
||||
|
||||
+ (nullable NSError *)migrateToSharedData
|
||||
{
|
||||
// Given how sensitive this migration is, we verbosely
|
||||
// log the contents of all involved paths before and after.
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSString *)databaseFilePath
|
||||
{
|
||||
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.sharedManager.dbReadConnection;
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)dbReadConnection
|
||||
{
|
||||
return self.dbReadPool.connection;
|
||||
}
|
||||
|
||||
+ (YapDatabaseConnection *)dbReadWriteConnection
|
||||
{
|
||||
return OWSPrimaryStorage.sharedManager.dbReadWriteConnection;
|
||||
}
|
||||
|
||||
#pragma mark - Misc.
|
||||
|
||||
- (void)touchDbAsync
|
||||
{
|
||||
// There appears to be a bug in YapDatabase that sometimes delays modifications
|
||||
// made in another process (e.g. the SAE) from showing up in other processes.
|
||||
// There's a simple workaround: a trivial write to the database flushes changes
|
||||
// made from other processes.
|
||||
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction setObject:[NSUUID UUID].UUIDString forKey:@"conversation_view_noop_mod" inCollection:@"temp"];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,32 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SessionMessagingKit/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
|
|
@ -1,116 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <YapDatabase/YapDatabase.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern NSString *const StorageIsReadyNotification;
|
||||
|
||||
@class YapDatabaseExtension;
|
||||
|
||||
@protocol OWSDatabaseConnectionDelegate <NSObject>
|
||||
|
||||
- (BOOL)areAllRegistrationsComplete;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSDatabaseConnection : YapDatabaseConnection
|
||||
|
||||
@property (atomic, weak) id<OWSDatabaseConnectionDelegate> delegate;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithDatabase:(YapDatabase *)database
|
||||
delegate:(id<OWSDatabaseConnectionDelegate>)delegate NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSDatabase : YapDatabase
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (id)initWithPath:(NSString *)inPath
|
||||
serializer:(nullable YapDatabaseSerializer)inSerializer
|
||||
deserializer:(YapDatabaseDeserializer)inDeserializer
|
||||
options:(YapDatabaseOptions *)inOptions
|
||||
delegate:(id<OWSDatabaseConnectionDelegate>)delegate NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
typedef void (^OWSStorageMigrationBlock)(void);
|
||||
|
||||
@interface OWSStorage : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initStorage 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;
|
||||
|
||||
// migrationBlock will be invoked _off_ the main thread.
|
||||
+ (void)registerExtensionsWithMigrationBlock:(OWSStorageMigrationBlock)migrationBlock;
|
||||
|
||||
#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<NSString *> *)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;
|
||||
|
||||
- (void)logFileSizes;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,808 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSStorage.h"
|
||||
#import "AppContext.h"
|
||||
#import "OWSBackgroundTask.h"
|
||||
#import "OWSFileSystem.h"
|
||||
#import "OWSPrimaryStorage.h"
|
||||
#import "TSYapDatabaseObject.h"
|
||||
#import <SignalCoreKit/SignalCoreKit.h>
|
||||
#import <SignalCoreKit/Randomness.h>
|
||||
#import <YapDatabase/YapDatabase.h>
|
||||
#import <YapDatabase/YapDatabaseAutoView.h>
|
||||
#import <YapDatabase/YapDatabaseCryptoUtils.h>
|
||||
#import <YapDatabase/YapDatabaseCrossProcessNotification.h>
|
||||
#import <YapDatabase/YapDatabaseFullTextSearch.h>
|
||||
#import <YapDatabase/YapDatabaseFullTextSearchPrivate.h>
|
||||
#import <YapDatabase/YapDatabaseSecondaryIndex.h>
|
||||
#import <YapDatabase/YapDatabaseSecondaryIndexPrivate.h>
|
||||
#import <YapDatabase/YapDatabaseSecondaryIndexSetup.h>
|
||||
#import <SessionUtilitiesKit/SessionUtilitiesKit.h>
|
||||
#import <SessionUtilitiesKit/AppContext.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSString *const StorageIsReadyNotification = @"StorageIsReadyNotification";
|
||||
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 -
|
||||
|
||||
@interface YapDatabaseConnection ()
|
||||
|
||||
- (id)initWithDatabase:(YapDatabase *)database;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSDatabaseConnection
|
||||
|
||||
- (id)initWithDatabase:(YapDatabase *)database delegate:(id<OWSDatabaseConnectionDelegate>)delegate
|
||||
{
|
||||
self = [super initWithDatabase:database];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
self.delegate = delegate;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
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
|
||||
{
|
||||
__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<OWSDatabaseConnectionDelegate> delegate;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSDatabase
|
||||
|
||||
- (id)initWithPath:(NSString *)inPath
|
||||
serializer:(nullable YapDatabaseSerializer)inSerializer
|
||||
deserializer:(YapDatabaseDeserializer)inDeserializer
|
||||
options:(YapDatabaseOptions *)inOptions
|
||||
delegate:(id<OWSDatabaseConnectionDelegate>)delegate
|
||||
{
|
||||
self = [super initWithPath:inPath serializer:inSerializer deserializer:inDeserializer options:inOptions];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
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<OWSDatabaseConnectionDelegate> delegate = self.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 : TSYapDatabaseObject <NSCoding>
|
||||
|
||||
@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
|
||||
{
|
||||
return [super encodeWithCoder:aCoder];
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
// No-op.
|
||||
}
|
||||
|
||||
- (void)touchWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
// No-op.
|
||||
}
|
||||
|
||||
- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
// No-op.
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSUnarchiverDelegate : NSObject <NSKeyedUnarchiverDelegate>
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSUnarchiverDelegate
|
||||
|
||||
- (nullable Class)unarchiver:(NSKeyedUnarchiver *)unarchiver
|
||||
cannotDecodeObjectOfClassName:(NSString *)name
|
||||
originalClasses:(NSArray<NSString *> *)classNames
|
||||
{
|
||||
return [OWSUnknownDBObject class];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSStorage () <OWSDatabaseConnectionDelegate>
|
||||
|
||||
@property (atomic, nullable) YapDatabase *database;
|
||||
|
||||
@property (nonatomic) NSMutableArray<NSString *> *extensionNames;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSStorage
|
||||
|
||||
- (instancetype)initStorage
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(resetStorage)
|
||||
name:OWSResetStorageNotification
|
||||
object:nil];
|
||||
|
||||
self.extensionNames = [NSMutableArray new];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[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.
|
||||
|
||||
// Try to reset app by deleting all databases.
|
||||
//
|
||||
// TODO: Possibly clean up all app files.
|
||||
// [OWSStorage deleteDatabaseFiles];
|
||||
|
||||
if (![self tryToLoadDatabase]) {
|
||||
|
||||
// Sleep to give analytics events time to be delivered.
|
||||
[NSThread sleepForTimeInterval:15.0f];
|
||||
|
||||
NSAssert(NO, @"Couldn't load database");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable id)dbNotificationObject
|
||||
{
|
||||
return self.database;
|
||||
}
|
||||
|
||||
- (BOOL)areAsyncRegistrationsComplete
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)areSyncRegistrationsComplete
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)areAllRegistrationsComplete
|
||||
{
|
||||
return self.areSyncRegistrationsComplete && self.areAsyncRegistrationsComplete;
|
||||
}
|
||||
|
||||
- (void)runSyncRegistrations
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)runAsyncRegistrationsWithCompletion:(void (^_Nonnull)(void))completion
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
+ (void)registerExtensionsWithMigrationBlock:(OWSStorageMigrationBlock)migrationBlock
|
||||
{
|
||||
__block OWSBackgroundTask *_Nullable backgroundTask =
|
||||
[OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
|
||||
|
||||
[OWSPrimaryStorage.sharedManager runSyncRegistrations];
|
||||
|
||||
[OWSPrimaryStorage.sharedManager runAsyncRegistrationsWithCompletion:^{
|
||||
[self postRegistrationCompleteNotification];
|
||||
|
||||
migrationBlock();
|
||||
|
||||
backgroundTask = nil;
|
||||
}];
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)registrationConnection
|
||||
{
|
||||
return self.database.registrationConnection;
|
||||
}
|
||||
|
||||
// Returns YES IFF all registrations are complete.
|
||||
+ (void)postRegistrationCompleteNotification
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationNameAsync:StorageIsReadyNotification
|
||||
object:nil
|
||||
userInfo:nil];
|
||||
});
|
||||
}
|
||||
|
||||
+ (BOOL)isStorageReady
|
||||
{
|
||||
return OWSPrimaryStorage.sharedManager.areAllRegistrationsComplete;
|
||||
}
|
||||
|
||||
+ (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;
|
||||
|
||||
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;
|
||||
|
||||
// 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];
|
||||
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) {
|
||||
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
|
||||
@throw exception;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)newDatabaseConnection
|
||||
{
|
||||
YapDatabaseConnection *dbConnection = self.database.newConnection;
|
||||
return dbConnection;
|
||||
}
|
||||
|
||||
#pragma mark - Extension Registration
|
||||
|
||||
+ (void)incrementVersionOfDatabaseExtension:(NSString *)extensionName
|
||||
{
|
||||
// Don't increment version of a given extension more than once
|
||||
// per launch.
|
||||
static NSMutableSet<NSString *> *incrementedViewSet = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
incrementedViewSet = [NSMutableSet new];
|
||||
});
|
||||
@synchronized(incrementedViewSet) {
|
||||
if ([incrementedViewSet containsObject:extensionName]) {
|
||||
return;
|
||||
}
|
||||
[incrementedViewSet addObject:extensionName];
|
||||
}
|
||||
|
||||
NSUserDefaults *appUserDefaults = [NSUserDefaults appUserDefaults];
|
||||
NSMutableDictionary<NSString *, NSNumber *> *_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
|
||||
{
|
||||
NSUserDefaults *appUserDefaults = [NSUserDefaults appUserDefaults];
|
||||
NSDictionary<NSString *, NSNumber *> *_Nullable versionMap =
|
||||
[appUserDefaults valueForKey:kNSUserDefaults_DatabaseExtensionVersionMap];
|
||||
NSNumber *_Nullable versionSuffix = versionMap[extensionName];
|
||||
|
||||
if (versionSuffix) {
|
||||
NSString *result =
|
||||
[NSString stringWithFormat:@"%@.%@", (versionTag.length < 1 ? @"0" : versionTag), versionSuffix];
|
||||
return result;
|
||||
}
|
||||
return versionTag;
|
||||
}
|
||||
|
||||
- (YapDatabaseExtension *)updateExtensionVersion:(YapDatabaseExtension *)extension withName:(NSString *)extensionName
|
||||
{
|
||||
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;
|
||||
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.
|
||||
|
||||
return extension;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName
|
||||
{
|
||||
extension = [self updateExtensionVersion:extension withName: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];
|
||||
|
||||
[self.extensionNames addObject:extensionName];
|
||||
|
||||
[self.database asyncRegisterExtension:extension
|
||||
withName:extensionName
|
||||
completionBlock:^(BOOL ready) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
- (nullable id)registeredExtension:(NSString *)extensionName
|
||||
{
|
||||
return [self.database registeredExtension:extensionName];
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)registeredExtensionNames
|
||||
{
|
||||
return [self.extensionNames copy];
|
||||
}
|
||||
|
||||
#pragma mark - Password
|
||||
|
||||
+ (void)deleteDatabaseFiles
|
||||
{
|
||||
[OWSFileSystem deleteFile:[OWSPrimaryStorage legacyDatabaseFilePath]];
|
||||
[OWSFileSystem deleteFile:[OWSPrimaryStorage legacyDatabaseFilePath_SHM]];
|
||||
[OWSFileSystem deleteFile:[OWSPrimaryStorage legacyDatabaseFilePath_WAL]];
|
||||
[OWSFileSystem deleteFile:[OWSPrimaryStorage sharedDataDatabaseFilePath]];
|
||||
[OWSFileSystem deleteFile:[OWSPrimaryStorage sharedDataDatabaseFilePath_SHM]];
|
||||
[OWSFileSystem deleteFile:[OWSPrimaryStorage sharedDataDatabaseFilePath_WAL]];
|
||||
}
|
||||
|
||||
- (void)closeStorageForTests
|
||||
{
|
||||
[self resetStorage];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)resetStorage
|
||||
{
|
||||
self.database = nil;
|
||||
|
||||
[OWSStorage deleteDatabaseFiles];
|
||||
}
|
||||
|
||||
+ (void)resetAllStorage
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:OWSResetStorageNotification object:nil];
|
||||
|
||||
// This might be redundant but in the spirit of thoroughness...
|
||||
[self deleteDatabaseFiles];
|
||||
|
||||
[self deleteDBKeys];
|
||||
|
||||
if (CurrentAppContext().isMainApp) {
|
||||
[TSAttachmentStream deleteAttachments];
|
||||
}
|
||||
|
||||
// TODO: Delete Profiles on Disk?
|
||||
}
|
||||
|
||||
#pragma mark - Password
|
||||
|
||||
- (NSString *)databaseFilePath
|
||||
{
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSString *)databaseFilePath_SHM
|
||||
{
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSString *)databaseFilePath_WAL
|
||||
{
|
||||
return @"";
|
||||
}
|
||||
|
||||
#pragma mark - Keychain
|
||||
|
||||
+ (BOOL)isDatabasePasswordAccessible
|
||||
{
|
||||
NSError *error;
|
||||
NSData *cipherKeySpec = [self tryToLoadDatabaseCipherKeySpec:&error];
|
||||
|
||||
if (cipherKeySpec && !error) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
+ (void)storeDatabaseCipherKeySpec:(NSData *)cipherKeySpecData
|
||||
{
|
||||
[self storeKeyChainValue:cipherKeySpecData keychainKey:keychainDBCipherKeySpec];
|
||||
}
|
||||
|
||||
+ (void)removeLegacyPassphrase
|
||||
{
|
||||
NSError *_Nullable error;
|
||||
BOOL result = [CurrentAppContext().keychainStorage removeWithService:keychainService
|
||||
key:keychainDBLegacyPassphrase
|
||||
error:&error];
|
||||
}
|
||||
|
||||
- (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)];
|
||||
}
|
||||
|
||||
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
|
||||
// or the keychain has become corrupt. Either way, we want to get back to a
|
||||
// "known good state" and behave like a new install.
|
||||
BOOL doesDBExist = [NSFileManager.defaultManager fileExistsAtPath:[self databaseFilePath]];
|
||||
|
||||
if (!CurrentAppContext().isRunningTests) {
|
||||
// Try to reset app by deleting database.
|
||||
[OWSStorage resetAllStorage];
|
||||
}
|
||||
|
||||
keySpec = [Randomness generateRandomBytes:(int)kSQLCipherKeySpecLength];
|
||||
[[self class] storeDatabaseCipherKeySpec:keySpec];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSData *)databaseKeySpec
|
||||
{
|
||||
NSError *error;
|
||||
NSData *_Nullable keySpec = [[self class] tryToLoadDatabaseCipherKeySpec:&error];
|
||||
|
||||
if (error) {
|
||||
[self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec inaccessible"];
|
||||
}
|
||||
|
||||
if (keySpec.length != kSQLCipherKeySpecLength) {
|
||||
[self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec invalid"];
|
||||
}
|
||||
|
||||
return keySpec;
|
||||
}
|
||||
|
||||
- (void)raiseKeySpecInaccessibleExceptionWithErrorDescription:(NSString *)errorDescription
|
||||
{
|
||||
// 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
|
||||
}
|
||||
|
||||
+ (void)deleteDBKeys
|
||||
{
|
||||
NSError *_Nullable error;
|
||||
BOOL result = [CurrentAppContext().keychainStorage removeWithService:keychainService
|
||||
key:keychainDBLegacyPassphrase
|
||||
error:&error];
|
||||
result = [CurrentAppContext().keychainStorage removeWithService:keychainService
|
||||
key:keychainDBCipherKeySpec
|
||||
error:&error];
|
||||
}
|
||||
|
||||
- (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
|
||||
{
|
||||
NSData *_Nullable data =
|
||||
[CurrentAppContext().keychainStorage dataForService:keychainService key:keychainKey error:errorHandle];
|
||||
return data;
|
||||
}
|
||||
|
||||
+ (void)storeKeyChainValue:(NSData *)data keychainKey:(NSString *)keychainKey
|
||||
{
|
||||
NSError *error;
|
||||
BOOL success =
|
||||
[CurrentAppContext().keychainStorage setWithData:data service:keychainService key:keychainKey error:&error];
|
||||
if (!success || error) {
|
||||
|
||||
// Sleep to give analytics events time to be delivered.
|
||||
[NSThread sleepForTimeInterval:15.0f];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
- (void)logFileSizes
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,209 +0,0 @@
|
|||
|
||||
extension Storage {
|
||||
|
||||
// MARK: - Open Groups
|
||||
|
||||
private static let openGroupCollection = "SNOpenGroupCollection"
|
||||
|
||||
@objc public func getAllV2OpenGroups() -> [String:OpenGroupV2] {
|
||||
var result = [String:OpenGroupV2]()
|
||||
Storage.read { transaction in
|
||||
transaction.enumerateKeysAndObjects(inCollection: Storage.openGroupCollection) { threadID, object, _ in
|
||||
guard let openGroup = object as? OpenGroupV2 else { return }
|
||||
result[threadID] = openGroup
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@objc(getV2OpenGroupForThreadID:)
|
||||
public func getV2OpenGroup(for threadID: String) -> OpenGroupV2? {
|
||||
var result: OpenGroupV2?
|
||||
Storage.read { transaction in
|
||||
result = transaction.object(forKey: threadID, inCollection: Storage.openGroupCollection) as? OpenGroupV2
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func v2GetThreadID(for v2OpenGroupID: String) -> String? {
|
||||
var result: String?
|
||||
Storage.read { transaction in
|
||||
transaction.enumerateKeysAndObjects(inCollection: Storage.openGroupCollection, using: { threadID, object, stop in
|
||||
guard let openGroup = object as? OpenGroupV2, openGroup.id == v2OpenGroupID else { return }
|
||||
result = threadID
|
||||
stop.pointee = true
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@objc(setV2OpenGroup:forThreadWithID:using:)
|
||||
public func setV2OpenGroup(_ openGroup: OpenGroupV2, for threadID: String, using transaction: Any) {
|
||||
(transaction as! YapDatabaseReadWriteTransaction).setObject(openGroup, forKey: threadID, inCollection: Storage.openGroupCollection)
|
||||
}
|
||||
|
||||
@objc(removeV2OpenGroupForThreadID:using:)
|
||||
public func removeV2OpenGroup(for threadID: String, using transaction: Any) {
|
||||
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: threadID, inCollection: Storage.openGroupCollection)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: - Authorization
|
||||
|
||||
private static let authTokenCollection = "SNAuthTokenCollection"
|
||||
|
||||
public func getAuthToken(for room: String, on server: String) -> String? {
|
||||
let collection = Storage.authTokenCollection
|
||||
let key = "\(server).\(room)"
|
||||
var result: String? = nil
|
||||
Storage.read { transaction in
|
||||
result = transaction.object(forKey: key, inCollection: collection) as? String
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func setAuthToken(for room: String, on server: String, to newValue: String, using transaction: Any) {
|
||||
let collection = Storage.authTokenCollection
|
||||
let key = "\(server).\(room)"
|
||||
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: key, inCollection: collection)
|
||||
}
|
||||
|
||||
public func removeAuthToken(for room: String, on server: String, using transaction: Any) {
|
||||
let collection = Storage.authTokenCollection
|
||||
let key = "\(server).\(room)"
|
||||
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: key, inCollection: collection)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: - Public Keys
|
||||
|
||||
private static let openGroupPublicKeyCollection = "LokiOpenGroupPublicKeyCollection"
|
||||
|
||||
public func getOpenGroupPublicKey(for server: String) -> String? {
|
||||
var result: String? = nil
|
||||
Storage.read { transaction in
|
||||
result = transaction.object(forKey: server, inCollection: Storage.openGroupPublicKeyCollection) as? String
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func setOpenGroupPublicKey(for server: String, to newValue: String, using transaction: Any) {
|
||||
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: server, inCollection: Storage.openGroupPublicKeyCollection)
|
||||
}
|
||||
|
||||
public func removeOpenGroupPublicKey(for server: String, using transaction: Any) {
|
||||
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: server, inCollection: Storage.openGroupPublicKeyCollection)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: - Last Message Server ID
|
||||
|
||||
public static let lastMessageServerIDCollection = "SNLastMessageServerIDCollection"
|
||||
|
||||
public func getLastMessageServerID(for room: String, on server: String) -> Int64? {
|
||||
let collection = Storage.lastMessageServerIDCollection
|
||||
let key = "\(server).\(room)"
|
||||
var result: Int64? = nil
|
||||
Storage.read { transaction in
|
||||
result = transaction.object(forKey: key, inCollection: collection) as? Int64
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func setLastMessageServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any) {
|
||||
let collection = Storage.lastMessageServerIDCollection
|
||||
let key = "\(server).\(room)"
|
||||
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: key, inCollection: collection)
|
||||
}
|
||||
|
||||
public func removeLastMessageServerID(for room: String, on server: String, using transaction: Any) {
|
||||
let collection = Storage.lastMessageServerIDCollection
|
||||
let key = "\(server).\(room)"
|
||||
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: key, inCollection: collection)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: - Last Deletion Server ID
|
||||
|
||||
public static let lastDeletionServerIDCollection = "SNLastDeletionServerIDCollection"
|
||||
|
||||
public func getLastDeletionServerID(for room: String, on server: String) -> Int64? {
|
||||
let collection = Storage.lastDeletionServerIDCollection
|
||||
let key = "\(server).\(room)"
|
||||
var result: Int64? = nil
|
||||
Storage.read { transaction in
|
||||
result = transaction.object(forKey: key, inCollection: collection) as? Int64
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func setLastDeletionServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any) {
|
||||
let collection = Storage.lastDeletionServerIDCollection
|
||||
let key = "\(server).\(room)"
|
||||
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: key, inCollection: collection)
|
||||
}
|
||||
|
||||
public func removeLastDeletionServerID(for room: String, on server: String, using transaction: Any) {
|
||||
let collection = Storage.lastDeletionServerIDCollection
|
||||
let key = "\(server).\(room)"
|
||||
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: key, inCollection: collection)
|
||||
}
|
||||
|
||||
// MARK: - OpenGroupServerIdToUniqueIdLookup
|
||||
|
||||
public static let openGroupServerIdToUniqueIdLookupCollection = "SNOpenGroupServerIdToUniqueIdLookup"
|
||||
|
||||
public func getOpenGroupServerIdLookup(_ serverId: UInt64, in room: String, on server: String, using transaction: YapDatabaseReadTransaction) -> OpenGroupServerIdLookup? {
|
||||
let key: String = OpenGroupServerIdLookup.id(serverId: serverId, in: room, on: server)
|
||||
return transaction.object(forKey: key, inCollection: Storage.openGroupServerIdToUniqueIdLookupCollection) as? OpenGroupServerIdLookup
|
||||
}
|
||||
|
||||
public func addOpenGroupServerIdLookup(_ serverId: UInt64?, tsMessageId: String?, in room: String, on server: String, using transaction: YapDatabaseReadWriteTransaction) {
|
||||
guard let serverId: UInt64 = serverId, let tsMessageId: String = tsMessageId else { return }
|
||||
|
||||
let lookup: OpenGroupServerIdLookup = OpenGroupServerIdLookup(server: server, room: room, serverId: serverId, tsMessageId: tsMessageId)
|
||||
addOpenGroupServerIdLookup(lookup, using: transaction)
|
||||
}
|
||||
|
||||
public func addOpenGroupServerIdLookup(_ lookup: OpenGroupServerIdLookup, using transaction: YapDatabaseReadWriteTransaction) {
|
||||
transaction.setObject(lookup, forKey: lookup.id, inCollection: Storage.openGroupServerIdToUniqueIdLookupCollection)
|
||||
}
|
||||
|
||||
public func removeOpenGroupServerIdLookup(_ serverId: UInt64, in room: String, on server: String, using transaction: YapDatabaseReadWriteTransaction) {
|
||||
let key: String = OpenGroupServerIdLookup.id(serverId: serverId, in: room, on: server)
|
||||
transaction.removeObject(forKey: key, inCollection: Storage.openGroupServerIdToUniqueIdLookupCollection)
|
||||
}
|
||||
|
||||
// MARK: - Metadata
|
||||
|
||||
private static let openGroupUserCountCollection = "SNOpenGroupUserCountCollection"
|
||||
private static let openGroupImageCollection = "SNOpenGroupImageCollection"
|
||||
|
||||
public func getUserCount(forV2OpenGroupWithID openGroupID: String) -> UInt64? {
|
||||
var result: UInt64?
|
||||
Storage.read { transaction in
|
||||
result = transaction.object(forKey: openGroupID, inCollection: Storage.openGroupUserCountCollection) as? UInt64
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func setUserCount(to newValue: UInt64, forV2OpenGroupWithID openGroupID: String, using transaction: Any) {
|
||||
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: openGroupID, inCollection: Storage.openGroupUserCountCollection)
|
||||
}
|
||||
|
||||
public func getOpenGroupImage(for room: String, on server: String) -> Data? {
|
||||
var result: Data?
|
||||
Storage.read { transaction in
|
||||
result = transaction.object(forKey: "\(server).\(room)", inCollection: Storage.openGroupImageCollection) as? Data
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func setOpenGroupImage(to data: Data, for room: String, on server: String, using transaction: Any) {
|
||||
(transaction as! YapDatabaseReadWriteTransaction).setObject(data, forKey: "\(server).\(room)", inCollection: Storage.openGroupImageCollection)
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import PromiseKit
|
||||
import Sodium
|
||||
|
||||
extension Storage {
|
||||
|
||||
@discardableResult
|
||||
public func write(with block: @escaping (Any) -> Void) -> Promise<Void> {
|
||||
Storage.write(with: { block($0) })
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func write(with block: @escaping (Any) -> Void, completion: @escaping () -> Void) -> Promise<Void> {
|
||||
Storage.write(with: { block($0) }, completion: completion)
|
||||
}
|
||||
|
||||
public func writeSync(with block: @escaping (Any) -> Void) {
|
||||
Storage.writeSync { block($0) }
|
||||
}
|
||||
// @objc public func getUser() -> Legacy.Contact? {
|
||||
// return getUser(using: nil)
|
||||
// }
|
||||
//
|
||||
// public func getUser(using transaction: YapDatabaseReadTransaction?) -> Legacy.Contact? {
|
||||
// let userPublicKey = getUserHexEncodedPublicKey()
|
||||
// var result: Legacy.Contact?
|
||||
//
|
||||
// if let transaction = transaction {
|
||||
// result = Storage.shared.getContact(with: userPublicKey, using: transaction)
|
||||
// }
|
||||
// else {
|
||||
// Storage.read { transaction in
|
||||
// result = Storage.shared.getContact(with: userPublicKey, using: transaction)
|
||||
// }
|
||||
// }
|
||||
// return result
|
||||
// }
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <YapDatabase/YapDatabaseSecondaryIndex.h>
|
||||
#import <YapDatabase/YapDatabaseTransaction.h>
|
||||
|
||||
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
|
|
@ -1,53 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSDatabaseSecondaryIndexes.h"
|
||||
#import "OWSStorage.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
|
|
@ -1,69 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SessionMessagingKit/OWSStorage.h>
|
||||
#import <YapDatabase/YapDatabaseViewTransaction.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern NSString *const TSInboxGroup;
|
||||
extern NSString *const TSMessageRequestGroup;
|
||||
extern NSString *const TSArchiveGroup;
|
||||
extern NSString *const TSShareExtensionGroup;
|
||||
extern NSString *const TSUnreadIncomingMessagesGroup;
|
||||
extern NSString *const TSSecondaryDevicesGroup;
|
||||
|
||||
extern NSString *const TSThreadDatabaseViewExtensionName;
|
||||
extern NSString *const TSThreadShareExtensionDatabaseViewExtensionName;
|
||||
|
||||
extern NSString *const TSMessageDatabaseViewExtensionName;
|
||||
extern NSString *const TSMessageDatabaseViewExtensionName_Legacy;
|
||||
|
||||
extern NSString *const TSUnreadDatabaseViewExtensionName;
|
||||
extern NSString *const TSUnseenDatabaseViewExtensionName;
|
||||
extern NSString *const TSUnreadMentionDatabaseViewExtensionName;
|
||||
extern NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName;
|
||||
extern NSString *const TSThreadSpecialMessagesDatabaseViewExtensionName;
|
||||
|
||||
extern NSString *const TSSecondaryDevicesDatabaseViewExtensionName;
|
||||
|
||||
extern NSString *const TSLazyRestoreAttachmentsGroup;
|
||||
extern NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName;
|
||||
|
||||
@interface TSDatabaseView : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
#pragma mark - Views
|
||||
|
||||
// Returns the "unseen" database view if it is ready;
|
||||
// otherwise it returns the "unread" database view.
|
||||
+ (id)unseenDatabaseViewExtension:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
+ (id)threadOutgoingMessageDatabaseView:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
+ (id)threadSpecialMessagesDatabaseView:(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)asyncRegisterThreadOutgoingMessagesDatabaseView:(OWSStorage *)storage;
|
||||
|
||||
// Should be used for "mention indicator".
|
||||
//
|
||||
// Instances of OWSReadTracking for wasRead is NO and isUserMentioned is YES.
|
||||
+ (void)asyncRegisterUnreadMentionDatabaseView:(OWSStorage *)storage;
|
||||
|
||||
+ (void)asyncRegisterLazyRestoreAttachmentsDatabaseView:(OWSStorage *)storage;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,441 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSDatabaseView.h"
|
||||
#import <YapDatabase/YapDatabaseAutoView.h>
|
||||
#import <YapDatabase/YapDatabaseCrossProcessNotification.h>
|
||||
#import <YapDatabase/YapDatabaseViewTypes.h>
|
||||
#import <SessionUtilitiesKit/AppContext.h>
|
||||
#import <SessionUtilitiesKit/SessionUtilitiesKit-Swift.h>
|
||||
#import <SessionMessagingKit/SessionMessagingKit-Swift.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSString *const TSInboxGroup = @"TSInboxGroup";
|
||||
NSString *const TSMessageRequestGroup = @"TSMessageRequestGroup";
|
||||
NSString *const TSArchiveGroup = @"TSArchiveGroup";
|
||||
NSString *const TSShareExtensionGroup = @"TSShareExtensionGroup";
|
||||
|
||||
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";
|
||||
|
||||
NSString *const TSThreadShareExtensionDatabaseViewExtensionName = @"TSThreadShareExtensionDatabaseViewExtensionName";
|
||||
|
||||
// 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 TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionName";
|
||||
NSString *const TSUnseenDatabaseViewExtensionName = @"TSUnseenDatabaseViewExtensionName";
|
||||
NSString *const TSUnreadMentionDatabaseViewExtensionName = @"TSUnreadMentionDatabaseViewExtensionName";
|
||||
NSString *const TSThreadSpecialMessagesDatabaseViewExtensionName = @"TSThreadSpecialMessagesDatabaseViewExtensionName";
|
||||
NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesDatabaseViewExtensionName";
|
||||
NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName
|
||||
= @"TSLazyRestoreAttachmentsDatabaseViewExtensionName";
|
||||
NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup";
|
||||
|
||||
@interface OWSStorage (TSDatabaseView)
|
||||
|
||||
- (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation TSDatabaseView
|
||||
|
||||
+ (void)registerCrossProcessNotifier:(OWSStorage *)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
|
||||
{
|
||||
YapDatabaseView *existingView = [storage registeredExtension:viewName];
|
||||
if (existingView) {
|
||||
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)asyncRegisterUnreadMentionDatabaseView:(OWSStorage *)storage
|
||||
{
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
if ([object isKindOfClass:[TSIncomingMessage class]]) {
|
||||
TSIncomingMessage *message = (TSIncomingMessage *)object;
|
||||
if (!message.wasRead && message.isUserMentioned) {
|
||||
return message.uniqueThreadId;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}];
|
||||
|
||||
[self registerMessageDatabaseViewWithName:TSUnreadMentionDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"2"
|
||||
storage:storage];
|
||||
}
|
||||
|
||||
+ (void)asyncRegisterLegacyThreadInteractionsDatabaseView:(OWSStorage *)storage
|
||||
{
|
||||
YapDatabaseView *existingView = [storage registeredExtension:TSMessageDatabaseViewExtensionName_Legacy];
|
||||
if (existingView) {
|
||||
return;
|
||||
}
|
||||
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
if (![object isKindOfClass:[TSInteraction class]]) {
|
||||
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]]) {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
if (![object2 isKindOfClass:[TSInteraction class]]) {
|
||||
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)asyncRegisterThreadInteractionsDatabaseView:(OWSStorage *)storage
|
||||
{
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
if (![object isKindOfClass:[TSInteraction class]]) {
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
if (![object isKindOfClass:[TSThread class]]) {
|
||||
return nil;
|
||||
}
|
||||
TSThread *thread = (TSThread *)object;
|
||||
|
||||
if ([thread isMessageRequestUsingTransaction:transaction]) {
|
||||
// Don't show blocked threads at all
|
||||
if (thread.isBlocked) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return TSMessageRequestGroup;
|
||||
}
|
||||
else if (thread.shouldBeVisible) {
|
||||
// Do nothing; we never hide threads that have ever had a message.
|
||||
} else {
|
||||
YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSMessageDatabaseViewExtensionName];
|
||||
NSUInteger threadMessageCount = [viewTransaction numberOfItemsInGroup:thread.uniqueId];
|
||||
if (threadMessageCount < 1) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
return 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];
|
||||
|
||||
YapDatabaseView *shareExtensionThreadView = [storage registeredExtension:TSThreadShareExtensionDatabaseViewExtensionName];
|
||||
if (shareExtensionThreadView) {
|
||||
return;
|
||||
}
|
||||
|
||||
YapDatabaseViewGrouping *shareExtensionViewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
if (![object isKindOfClass:[TSThread class]]) {
|
||||
return nil;
|
||||
}
|
||||
TSThread *thread = (TSThread *)object;
|
||||
|
||||
if ([thread isMessageRequestUsingTransaction:transaction]) {
|
||||
return nil;
|
||||
}
|
||||
else {
|
||||
YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSMessageDatabaseViewExtensionName];
|
||||
NSUInteger threadMessageCount = [viewTransaction numberOfItemsInGroup:thread.uniqueId];
|
||||
if (threadMessageCount < 1) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!thread.isGroupThread) {
|
||||
TSContactThread *contactThead = (TSContactThread *)thread;
|
||||
SMKContact *contact = [SMKContact fetchOrCreateWithId:[contactThead contactSessionID]];
|
||||
|
||||
if (contact == nil || !contact.didApproveMe) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TSShareExtensionGroup;
|
||||
}];
|
||||
|
||||
YapDatabaseViewSorting *shareExtensionViewSorting = [self threadSorting];
|
||||
|
||||
YapDatabaseViewOptions *shareExtensionOptions = [[YapDatabaseViewOptions alloc] init];
|
||||
shareExtensionOptions.isPersistent = YES;
|
||||
shareExtensionOptions.allowedCollections =
|
||||
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSThread collection]]];
|
||||
|
||||
YapDatabaseView *shareExtensionDatabaseView =
|
||||
[[YapDatabaseAutoView alloc] initWithGrouping:shareExtensionViewGrouping sorting:shareExtensionViewSorting versionTag:@"1" options:shareExtensionOptions];
|
||||
|
||||
[storage asyncRegisterExtension:shareExtensionDatabaseView withName:TSThreadShareExtensionDatabaseViewExtensionName];
|
||||
}
|
||||
|
||||
+ (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]]) {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
if (![object2 isKindOfClass:[TSThread class]]) {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
TSThread *thread1 = (TSThread *)object1;
|
||||
TSThread *thread2 = (TSThread *)object2;
|
||||
if ([group isEqualToString:TSArchiveGroup] || [group isEqualToString:TSInboxGroup]) {
|
||||
if (thread1.isPinned != thread2.isPinned) {
|
||||
if (thread1.isPinned) { return NSOrderedDescending; }
|
||||
if (thread2.isPinned) { return NSOrderedAscending; }
|
||||
}
|
||||
TSInteraction *_Nullable lastInteractionForInbox1 =
|
||||
[thread1 lastInteractionForInboxWithTransaction:transaction];
|
||||
NSDate *lastInteractionForInboxDate1 = lastInteractionForInbox1 ? lastInteractionForInbox1.receivedAtDate : thread1.creationDate;
|
||||
|
||||
TSInteraction *_Nullable lastInteractionForInbox2 =
|
||||
[thread2 lastInteractionForInboxWithTransaction:transaction];
|
||||
NSDate *lastInteractionForInboxDate2 = lastInteractionForInbox2 ? lastInteractionForInbox2.receivedAtDate : thread2.creationDate;
|
||||
|
||||
|
||||
NSDate *date1 = thread1.lastInteractionDate ?: lastInteractionForInboxDate1 ?: thread1.creationDate;
|
||||
NSDate *date2 = thread2.lastInteractionDate ?: lastInteractionForInboxDate2 ?: thread2.creationDate;
|
||||
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]]) {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
if (![object2 isKindOfClass:[TSInteraction class]]) {
|
||||
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]]) {
|
||||
return nil;
|
||||
}
|
||||
if (![object isKindOfClass:[TSAttachmentPointer class]]) {
|
||||
return nil;
|
||||
}
|
||||
TSAttachmentPointer *attachmentPointer = (TSAttachmentPointer *)object;
|
||||
if (attachmentPointer.lazyRestoreFragment) {
|
||||
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]]) {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
if (![object2 isKindOfClass:[TSAttachmentPointer class]]) {
|
||||
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];
|
||||
}
|
||||
|
||||
+ (id)unseenDatabaseViewExtension:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
id _Nullable result = [transaction ext:TSUnseenDatabaseViewExtensionName];
|
||||
|
||||
// TODO: I believe we can now safely remove this?
|
||||
if (!result) {
|
||||
result = [transaction ext:TSUnreadDatabaseViewExtensionName];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// MJK TODO - dynamic interactions
|
||||
+ (id)threadOutgoingMessageDatabaseView:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
id result = [transaction ext:TSThreadOutgoingMessageDatabaseViewExtensionName];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (id)threadSpecialMessagesDatabaseView:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
id result = [transaction ext:TSThreadSpecialMessagesDatabaseViewExtensionName];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,5 +1,9 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import PromiseKit
|
||||
import SessionSnodeKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
@objc(SNFileServerAPIV2)
|
||||
public final class FileServerAPIV2 : NSObject {
|
||||
|
|
|
@ -7,13 +7,5 @@ FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[];
|
|||
#import <SessionMessagingKit/NSData+messagePadding.h>
|
||||
#import <SessionMessagingKit/OWSAudioPlayer.h>
|
||||
#import <SessionMessagingKit/OWSBackgroundTask.h>
|
||||
#import <SessionMessagingKit/OWSBackupFragment.h>
|
||||
#import <SessionMessagingKit/OWSPreferences.h>
|
||||
#import <SessionMessagingKit/OWSPrimaryStorage.h>
|
||||
#import <SessionMessagingKit/OWSStorage.h>
|
||||
#import <SessionMessagingKit/OWSStorage+Subclass.h>
|
||||
#import <SessionMessagingKit/OWSWindowManager.h>
|
||||
#import <SessionMessagingKit/TSDatabaseSecondaryIndexes.h>
|
||||
#import <SessionMessagingKit/TSDatabaseView.h>
|
||||
#import <SessionMessagingKit/YapDatabaseConnection+OWS.h>
|
||||
#import <SessionMessagingKit/YapDatabaseTransaction+OWS.h>
|
||||
|
|
|
@ -6,6 +6,7 @@ import Sodium
|
|||
import Curve25519Kit
|
||||
import SignalCoreKit
|
||||
import SessionSnodeKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
extension MessageReceiver {
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import GRDB
|
||||
import PromiseKit
|
||||
import SessionSnodeKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
@objc(LKPushNotificationAPI)
|
||||
public final class PushNotificationAPI : NSObject {
|
||||
|
|
|
@ -4,6 +4,7 @@ import Foundation
|
|||
import GRDB
|
||||
import PromiseKit
|
||||
import SessionSnodeKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
@objc(LKClosedGroupPoller)
|
||||
public final class ClosedGroupPoller: NSObject {
|
||||
|
|
|
@ -5,6 +5,7 @@ import GRDB
|
|||
import PromiseKit
|
||||
import Sodium
|
||||
import SessionSnodeKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public final class Poller {
|
||||
private var isPolling: Atomic<Bool> = Atomic(false)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import DifferenceKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
fileprivate typealias ViewModel = SessionThreadViewModel
|
||||
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
import PromiseKit
|
||||
import Sodium
|
||||
import SessionSnodeKit
|
||||
|
||||
public protocol SessionMessagingKitStorageProtocol {
|
||||
|
||||
// MARK: - Shared
|
||||
|
||||
@discardableResult
|
||||
func write(with block: @escaping (Any) -> Void) -> Promise<Void>
|
||||
@discardableResult
|
||||
func write(with block: @escaping (Any) -> Void, completion: @escaping () -> Void) -> Promise<Void>
|
||||
func writeSync(with block: @escaping (Any) -> Void)
|
||||
|
||||
// MARK: - Authorization
|
||||
|
||||
func getAuthToken(for room: String, on server: String) -> String?
|
||||
func setAuthToken(for room: String, on server: String, to newValue: String, using transaction: Any)
|
||||
func removeAuthToken(for room: String, on server: String, using transaction: Any)
|
||||
|
||||
// MARK: - Open Groups
|
||||
|
||||
func getAllV2OpenGroups() -> [String:OpenGroupV2]
|
||||
func getV2OpenGroup(for threadID: String) -> OpenGroupV2?
|
||||
func v2GetThreadID(for v2OpenGroupID: String) -> String?
|
||||
|
||||
// MARK: - Open Group Public Keys
|
||||
|
||||
func getOpenGroupPublicKey(for server: String) -> String?
|
||||
func setOpenGroupPublicKey(for server: String, to newValue: String, using transaction: Any)
|
||||
|
||||
// MARK: - Last Message Server ID
|
||||
|
||||
func getLastMessageServerID(for room: String, on server: String) -> Int64?
|
||||
func setLastMessageServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any)
|
||||
func removeLastMessageServerID(for room: String, on server: String, using transaction: Any)
|
||||
|
||||
// MARK: - Last Deletion Server ID
|
||||
|
||||
func getLastDeletionServerID(for room: String, on server: String) -> Int64?
|
||||
func setLastDeletionServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any)
|
||||
func removeLastDeletionServerID(for room: String, on server: String, using transaction: Any)
|
||||
|
||||
// MARK: - OpenGroupServerIdToUniqueIdLookup
|
||||
|
||||
func getOpenGroupServerIdLookup(_ serverId: UInt64, in room: String, on server: String, using transaction: YapDatabaseReadTransaction) -> OpenGroupServerIdLookup?
|
||||
func addOpenGroupServerIdLookup(_ serverId: UInt64?, tsMessageId: String?, in room: String, on server: String, using transaction: YapDatabaseReadWriteTransaction)
|
||||
func addOpenGroupServerIdLookup(_ lookup: OpenGroupServerIdLookup, using transaction: YapDatabaseReadWriteTransaction)
|
||||
func removeOpenGroupServerIdLookup(_ serverId: UInt64, in room: String, on server: String, using transaction: YapDatabaseReadWriteTransaction)
|
||||
|
||||
// MARK: - Open Group Metadata
|
||||
|
||||
func setUserCount(to newValue: UInt64, forV2OpenGroupWithID openGroupID: String, using transaction: Any)
|
||||
}
|
||||
|
||||
extension Storage: SessionMessagingKitStorageProtocol {}
|
|
@ -6,11 +6,9 @@ import SessionUtilitiesKit
|
|||
public class Environment {
|
||||
public static var shared: Environment!
|
||||
|
||||
public let primaryStorage: OWSPrimaryStorage
|
||||
public let reachabilityManager: SSKReachabilityManager
|
||||
|
||||
public let audioSession: OWSAudioSession
|
||||
public let preferences: OWSPreferences
|
||||
public let proximityMonitoringManager: OWSProximityMonitoringManager
|
||||
public let windowManager: OWSWindowManager
|
||||
public var isRequestingPermission: Bool
|
||||
|
@ -22,34 +20,20 @@ public class Environment {
|
|||
(notificationsManager.wrappedValue != nil)
|
||||
}
|
||||
|
||||
public var objectReadWriteConnection: YapDatabaseConnection
|
||||
public var sessionStoreDBConnection: YapDatabaseConnection
|
||||
public var migrationDBConnection: YapDatabaseConnection
|
||||
public var analyticsDBConnection: YapDatabaseConnection
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
public init(
|
||||
primaryStorage: OWSPrimaryStorage,
|
||||
reachabilityManager: SSKReachabilityManager,
|
||||
audioSession: OWSAudioSession,
|
||||
preferences: OWSPreferences,
|
||||
proximityMonitoringManager: OWSProximityMonitoringManager,
|
||||
windowManager: OWSWindowManager
|
||||
) {
|
||||
self.primaryStorage = primaryStorage
|
||||
self.reachabilityManager = reachabilityManager
|
||||
self.audioSession = audioSession
|
||||
self.preferences = preferences
|
||||
self.proximityMonitoringManager = proximityMonitoringManager
|
||||
self.windowManager = windowManager
|
||||
self.isRequestingPermission = false
|
||||
|
||||
self.objectReadWriteConnection = primaryStorage.newDatabaseConnection()
|
||||
self.sessionStoreDBConnection = primaryStorage.newDatabaseConnection()
|
||||
self.migrationDBConnection = primaryStorage.newDatabaseConnection()
|
||||
self.analyticsDBConnection = primaryStorage.newDatabaseConnection()
|
||||
|
||||
if Environment.shared == nil {
|
||||
Environment.shared = self
|
||||
}
|
||||
|
@ -68,7 +52,6 @@ public class Environment {
|
|||
class SMKEnvironment: NSObject {
|
||||
@objc public static let shared: SMKEnvironment = SMKEnvironment()
|
||||
|
||||
@objc public var primaryStorage: OWSPrimaryStorage { Environment.shared.primaryStorage }
|
||||
@objc public var audioSession: OWSAudioSession { Environment.shared.audioSession }
|
||||
@objc public var windowManager: OWSWindowManager { Environment.shared.windowManager }
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import Foundation
|
||||
import AVFoundation
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
@objc(OWSAudioActivity)
|
||||
public class AudioActivity: NSObject {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
@objc
|
||||
public protocol OWSProximityMonitoringManager: AnyObject {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import SessionSnodeKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public extension SNProtoEnvelope {
|
||||
static func from(_ message: SnodeReceivedMessage) -> SNProtoEnvelope? {
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <YapDatabase/YapDatabaseConnection.h>
|
||||
|
||||
@class ECKeyPair;
|
||||
@class PreKeyRecord;
|
||||
@class SignedPreKeyRecord;
|
||||
@class PreKeyBundle;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface YapDatabaseConnection (OWS)
|
||||
|
||||
- (BOOL)hasObjectForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (BOOL)boolForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(BOOL)defaultValue;
|
||||
- (double)doubleForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(double)defaultValue;
|
||||
- (int)intForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (nullable id)objectForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (nullable NSDate *)dateForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (nullable NSDictionary *)dictionaryForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (nullable NSString *)stringForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (nullable NSData *)dataForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (nullable ECKeyPair *)keyPairForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
|
||||
- (NSUInteger)numberOfKeysInCollection:(NSString *)collection;
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)setObject:(id)object forKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (void)setBool:(BOOL)value forKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (void)setDouble:(double)value forKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (void)removeObjectForKey:(NSString *)string inCollection:(NSString *)collection;
|
||||
- (void)setInt:(int)integer forKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (void)setDate:(NSDate *)value forKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (int)incrementIntForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
|
||||
- (void)purgeCollection:(NSString *)collection;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,154 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "YapDatabaseConnection+OWS.h"
|
||||
#import <Curve25519Kit/Curve25519.h>
|
||||
#import <YapDatabase/YapDatabaseTransaction.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation YapDatabaseConnection (OWS)
|
||||
|
||||
- (BOOL)hasObjectForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
return nil != [self objectForKey:key inCollection:collection];
|
||||
}
|
||||
|
||||
- (nullable id)objectForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
__block NSString *_Nullable object;
|
||||
|
||||
[self readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
object = [transaction objectForKey:key inCollection:collection];
|
||||
}];
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
- (nullable id)objectForKey:(NSString *)key inCollection:(NSString *)collection ofExpectedType:(Class)class
|
||||
{
|
||||
id _Nullable value = [self objectForKey:key inCollection:collection];
|
||||
return value;
|
||||
}
|
||||
|
||||
- (nullable NSDictionary *)dictionaryForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
return [self objectForKey:key inCollection:collection ofExpectedType:[NSDictionary class]];
|
||||
}
|
||||
|
||||
- (nullable NSString *)stringForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
return [self objectForKey:key inCollection:collection ofExpectedType:[NSString class]];
|
||||
}
|
||||
|
||||
- (BOOL)boolForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(BOOL)defaultValue
|
||||
{
|
||||
NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
|
||||
return value ? [value boolValue] : defaultValue;
|
||||
}
|
||||
|
||||
- (double)doubleForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(double)defaultValue
|
||||
{
|
||||
NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
|
||||
return value ? [value doubleValue] : defaultValue;
|
||||
}
|
||||
|
||||
- (nullable NSData *)dataForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
return [self objectForKey:key inCollection:collection ofExpectedType:[NSData class]];
|
||||
}
|
||||
|
||||
- (nullable ECKeyPair *)keyPairForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
return [self objectForKey:key inCollection:collection ofExpectedType:[ECKeyPair class]];
|
||||
}
|
||||
|
||||
- (int)intForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
NSNumber *_Nullable number = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
|
||||
return [number intValue];
|
||||
}
|
||||
|
||||
- (nullable NSDate *)dateForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
|
||||
if (value) {
|
||||
return [NSDate dateWithTimeIntervalSince1970:value.doubleValue];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSUInteger)numberOfKeysInCollection:(NSString *)collection
|
||||
{
|
||||
__block NSUInteger result;
|
||||
[self readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
result = [transaction numberOfKeysInCollection:collection];
|
||||
}];
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)purgeCollection:(NSString *)collection
|
||||
{
|
||||
[self readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:collection];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setObject:(id)object forKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
[self readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction setObject:object forKey:key inCollection:collection];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setBool:(BOOL)value forKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
NSNumber *_Nullable oldValue = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
|
||||
if (oldValue && [@(value) isEqual:oldValue]) {
|
||||
// Skip redundant writes.
|
||||
return;
|
||||
}
|
||||
|
||||
[self setObject:@(value) forKey:key inCollection:collection];
|
||||
}
|
||||
|
||||
- (void)setDouble:(double)value forKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
[self setObject:@(value) forKey:key inCollection:collection];
|
||||
}
|
||||
|
||||
- (void)removeObjectForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
[self readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeObjectForKey:key inCollection:collection];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setInt:(int)value forKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
[self setObject:@(value) forKey:key inCollection:collection];
|
||||
}
|
||||
|
||||
- (int)incrementIntForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
__block int value = 0;
|
||||
[self readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
value = [[transaction objectForKey:key inCollection:collection] intValue];
|
||||
value++;
|
||||
[transaction setObject:@(value) forKey:key inCollection:collection];
|
||||
}];
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setDate:(NSDate *)value forKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
[self setObject:@(value.timeIntervalSince1970) forKey:key inCollection:collection];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,43 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <YapDatabase/YapDatabaseTransaction.h>
|
||||
|
||||
@class ECKeyPair;
|
||||
@class PreKeyRecord;
|
||||
@class PreKeyBundle;
|
||||
@class SignedPreKeyRecord;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface YapDatabaseReadTransaction (OWS)
|
||||
|
||||
- (BOOL)boolForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(BOOL)defaultValue;
|
||||
- (double)doubleForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(double)defaultValue;
|
||||
- (int)intForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (nullable NSDate *)dateForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (nullable NSDictionary *)dictionaryForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (nullable NSString *)stringForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (nullable NSData *)dataForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (nullable ECKeyPair *)keyPairForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface YapDatabaseReadWriteTransaction (OWS)
|
||||
|
||||
#pragma mark - Debug
|
||||
|
||||
#if DEBUG
|
||||
- (void)snapshotCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath;
|
||||
- (void)restoreSnapshotOfCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath;
|
||||
#endif
|
||||
|
||||
- (void)setBool:(BOOL)value forKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (void)setDate:(NSDate *)value forKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,116 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "YapDatabaseTransaction+OWS.h"
|
||||
#import <Curve25519Kit/Curve25519.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation YapDatabaseReadTransaction (OWS)
|
||||
|
||||
- (nullable id)objectForKey:(NSString *)key inCollection:(NSString *)collection ofExpectedType:(Class) class {
|
||||
id _Nullable value = [self objectForKey:key inCollection:collection];
|
||||
return value;
|
||||
}
|
||||
|
||||
- (nullable NSDictionary *)dictionaryForKey : (NSString *)key inCollection : (NSString *)collection
|
||||
{
|
||||
return [self objectForKey:key inCollection:collection ofExpectedType:[NSDictionary class]];
|
||||
}
|
||||
|
||||
- (nullable NSString *)stringForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
return [self objectForKey:key inCollection:collection ofExpectedType:[NSString class]];
|
||||
}
|
||||
|
||||
- (BOOL)boolForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(BOOL)defaultValue
|
||||
{
|
||||
NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
|
||||
return value ? [value boolValue] : defaultValue;
|
||||
}
|
||||
|
||||
- (double)doubleForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(double)defaultValue
|
||||
{
|
||||
NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
|
||||
return value ? [value doubleValue] : defaultValue;
|
||||
}
|
||||
|
||||
- (nullable NSData *)dataForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
return [self objectForKey:key inCollection:collection ofExpectedType:[NSData class]];
|
||||
}
|
||||
|
||||
- (nullable ECKeyPair *)keyPairForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
return [self objectForKey:key inCollection:collection ofExpectedType:[ECKeyPair class]];
|
||||
}
|
||||
|
||||
- (int)intForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
NSNumber *_Nullable number = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
|
||||
return [number intValue];
|
||||
}
|
||||
|
||||
- (nullable NSDate *)dateForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
|
||||
if (value) {
|
||||
return [NSDate dateWithTimeIntervalSince1970:value.doubleValue];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation YapDatabaseReadWriteTransaction (OWS)
|
||||
|
||||
#pragma mark - Debug
|
||||
|
||||
#if DEBUG
|
||||
- (void)snapshotCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath
|
||||
{
|
||||
NSMutableDictionary<NSString *, id> *snapshot = [NSMutableDictionary new];
|
||||
[self enumerateKeysAndObjectsInCollection:collection
|
||||
usingBlock:^(NSString *_Nonnull key, id _Nonnull value, BOOL *_Nonnull stop) {
|
||||
snapshot[key] = value;
|
||||
}];
|
||||
NSData *_Nullable data = [NSKeyedArchiver archivedDataWithRootObject:snapshot];
|
||||
BOOL success = [data writeToFile:snapshotFilePath atomically:YES];
|
||||
}
|
||||
|
||||
- (void)restoreSnapshotOfCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath
|
||||
{
|
||||
|
||||
NSData *_Nullable data = [NSData dataWithContentsOfFile:snapshotFilePath];
|
||||
NSMutableDictionary<NSString *, id> *_Nullable snapshot = [NSKeyedUnarchiver unarchiveObjectWithData:data];
|
||||
|
||||
[self removeAllObjectsInCollection:collection];
|
||||
[snapshot enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, id _Nonnull value, BOOL *_Nonnull stop) {
|
||||
[self setObject:value forKey:key inCollection:collection];
|
||||
}];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)setBool:(BOOL)value forKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
NSNumber *_Nullable oldValue = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
|
||||
if (oldValue && [@(value) isEqual:oldValue]) {
|
||||
// Skip redundant writes.
|
||||
return;
|
||||
}
|
||||
|
||||
[self setObject:@(value) forKey:key inCollection:collection];
|
||||
}
|
||||
|
||||
- (void)setDate:(NSDate *)value forKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
[self setObject:@(value.timeIntervalSince1970) forKey:key inCollection:collection];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -125,8 +125,6 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
|
|||
completion()
|
||||
}
|
||||
)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(storageIsReady), name: .StorageIsReady, object: nil)
|
||||
}
|
||||
|
||||
@objc
|
||||
|
@ -145,13 +143,6 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
|
|||
checkIsAppReady()
|
||||
}
|
||||
|
||||
@objc
|
||||
private func storageIsReady() {
|
||||
AssertIsOnMainThread()
|
||||
|
||||
checkIsAppReady()
|
||||
}
|
||||
|
||||
@objc
|
||||
private func checkIsAppReady() {
|
||||
AssertIsOnMainThread()
|
||||
|
@ -160,7 +151,7 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
|
|||
guard !AppReadiness.isAppReady() else { return }
|
||||
|
||||
// App isn't ready until storage is ready AND all version migrations are complete.
|
||||
guard OWSStorage.isStorageReady() && areVersionMigrationsComplete else { return }
|
||||
guard GRDBStorage.shared.isValid && areVersionMigrationsComplete else { return }
|
||||
|
||||
SignalUtilitiesKit.Configuration.performMainSetup()
|
||||
|
||||
|
|
|
@ -56,13 +56,6 @@ final class ShareVC : UINavigationController, ShareViewDelegate, AppModeManagerD
|
|||
)
|
||||
|
||||
// We don't need to use "screen protection" in the SAE.
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(storageIsReady),
|
||||
name: .StorageIsReady,
|
||||
object: nil
|
||||
)
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(applicationDidEnterBackground),
|
||||
|
@ -89,22 +82,13 @@ final class ShareVC : UINavigationController, ShareViewDelegate, AppModeManagerD
|
|||
checkIsAppReady()
|
||||
}
|
||||
|
||||
@objc
|
||||
func storageIsReady() {
|
||||
AssertIsOnMainThread()
|
||||
|
||||
Logger.debug("")
|
||||
|
||||
checkIsAppReady()
|
||||
}
|
||||
|
||||
@objc
|
||||
func checkIsAppReady() {
|
||||
AssertIsOnMainThread()
|
||||
|
||||
// App isn't ready until storage is ready AND all version migrations are complete.
|
||||
guard areVersionMigrationsComplete else { return }
|
||||
guard OWSStorage.isStorageReady() else { return }
|
||||
guard GRDBStorage.shared.isValid else { return }
|
||||
guard !AppReadiness.isAppReady() else {
|
||||
// Only mark the app as ready once.
|
||||
return
|
||||
|
|
|
@ -3,10 +3,6 @@
|
|||
import Foundation
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public struct SNSnodeKitConfiguration {
|
||||
internal static var shared: SNSnodeKitConfiguration!
|
||||
}
|
||||
|
||||
public enum SNSnodeKit { // Just to make the external API nice
|
||||
public static func migrations() -> TargetMigrations {
|
||||
return TargetMigrations(
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import YapDatabase
|
||||
import SessionUtilitiesKit
|
||||
|
||||
enum _003_YDBToGRDBMigration: Migration {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc
|
||||
public final class SNUtilitiesKitConfiguration : NSObject {
|
||||
@objc public let owsPrimaryStorage: OWSPrimaryStorageProtocol
|
||||
public let maxFileSize: UInt
|
||||
|
||||
@objc public static var shared: SNUtilitiesKitConfiguration!
|
||||
|
||||
fileprivate init(owsPrimaryStorage: OWSPrimaryStorageProtocol, maxFileSize: UInt) {
|
||||
self.owsPrimaryStorage = owsPrimaryStorage
|
||||
fileprivate init(maxFileSize: UInt) {
|
||||
self.maxFileSize = maxFileSize
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +30,7 @@ public enum SNUtilitiesKit { // Just to make the external API nice
|
|||
)
|
||||
}
|
||||
|
||||
public static func configure(owsPrimaryStorage: OWSPrimaryStorageProtocol, maxFileSize: UInt) {
|
||||
SNUtilitiesKitConfiguration.shared = SNUtilitiesKitConfiguration(owsPrimaryStorage: owsPrimaryStorage, maxFileSize: maxFileSize)
|
||||
public static func configure(maxFileSize: UInt) {
|
||||
SNUtilitiesKitConfiguration.shared = SNUtilitiesKitConfiguration(maxFileSize: maxFileSize)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -257,7 +257,7 @@ public final class GRDBStorage {
|
|||
|
||||
// MARK: - File Management
|
||||
|
||||
private static func resetAllStorage() {
|
||||
public static func resetAllStorage() {
|
||||
NotificationCenter.default.post(name: .resetStorage, object: nil)
|
||||
|
||||
// This might be redundant but in the spirit of thoroughness...
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import YapDatabase
|
||||
|
||||
enum _003_YDBToGRDBMigration: Migration {
|
||||
static let target: TargetMigrations.Identifier = .utilitiesKit
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
import YapDatabase
|
||||
|
||||
@objc public protocol OWSPrimaryStorageProtocol {
|
||||
|
||||
var dbReadConnection: YapDatabaseConnection { get }
|
||||
var dbReadWriteConnection: YapDatabaseConnection { get }
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
import PromiseKit
|
||||
import YapDatabase
|
||||
|
||||
// Some important notes about YapDatabase:
|
||||
//
|
||||
// • Connections are thread-safe.
|
||||
// • Executing a write transaction from within a write transaction is NOT allowed.
|
||||
|
||||
@objc(LKStorage)
|
||||
public final class Storage : NSObject {
|
||||
public static let serialQueue = DispatchQueue(label: "Storage.serialQueue", qos: .userInitiated)
|
||||
|
||||
private static var owsStorage: OWSPrimaryStorageProtocol { SNUtilitiesKitConfiguration.shared.owsPrimaryStorage }
|
||||
|
||||
@objc public static let shared = Storage()
|
||||
|
||||
// MARK: Reading
|
||||
|
||||
// Some important points regarding reading from the database:
|
||||
//
|
||||
// • Background threads should use `OWSPrimaryStorage`'s `dbReadConnection`, whereas the main thread should use `OWSPrimaryStorage`'s `uiDatabaseConnection` (see the `YapDatabaseConnectionPool` documentation for more information).
|
||||
// • Multiple read transactions can safely be executed at the same time.
|
||||
|
||||
@objc(readWithBlock:)
|
||||
public static func read(with block: @escaping (YapDatabaseReadTransaction) -> Void) {
|
||||
owsStorage.dbReadConnection.read(block)
|
||||
}
|
||||
|
||||
// MARK: Writing
|
||||
|
||||
// Some important points regarding writing to the database:
|
||||
//
|
||||
// • There can only be a single write transaction per database at any one time, so all write transactions must use `OWSPrimaryStorage`'s `dbReadWriteConnection`.
|
||||
// • Executing a write transaction from within a write transaction causes a deadlock and must be avoided.
|
||||
|
||||
@discardableResult
|
||||
@objc(writeWithBlock:)
|
||||
public static func objc_write(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) -> AnyPromise {
|
||||
return AnyPromise.from(write(with: block) { })
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public static func write(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) -> Promise<Void> {
|
||||
return write(with: block) { }
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
@objc(writeWithBlock:completion:)
|
||||
public static func objc_write(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void, completion: @escaping () -> Void) -> AnyPromise {
|
||||
return AnyPromise.from(write(with: block, completion: completion))
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public static func write(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void, completion: @escaping () -> Void) -> Promise<Void> {
|
||||
let (promise, seal) = Promise<Void>.pending()
|
||||
serialQueue.async {
|
||||
owsStorage.dbReadWriteConnection.readWrite { transaction in
|
||||
transaction.addCompletionQueue(DispatchQueue.main, completionBlock: completion)
|
||||
block(transaction)
|
||||
}
|
||||
seal.fulfill(())
|
||||
}
|
||||
return promise
|
||||
}
|
||||
|
||||
/// Blocks the calling thread until the write has finished.
|
||||
@objc(writeSyncWithBlock:)
|
||||
public static func writeSync(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) {
|
||||
try! write(with: block, completion: { }).wait() // The promise returned by write(with:completion:) never rejects
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <YapDatabase/YapDatabase.h>
|
||||
#import <Mantle/MTLModel+NSCoding.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class OWSPrimaryStorage;
|
||||
@class YapDatabaseConnection;
|
||||
@class YapDatabaseReadTransaction;
|
||||
@class YapDatabaseReadWriteTransaction;
|
||||
|
||||
@interface TSYapDatabaseObject : MTLModel
|
||||
|
||||
- (instancetype)init NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Initializes a new database object with a unique identifier
|
||||
*
|
||||
* @param uniqueId Key used for the key-value store
|
||||
*
|
||||
* @return Initialized object
|
||||
*/
|
||||
- (instancetype)initWithUniqueId:(NSString *_Nullable)uniqueId NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Returns the collection to which the object belongs.
|
||||
*
|
||||
* @return Key (string) identifying the collection
|
||||
*/
|
||||
+ (NSString *)collection;
|
||||
|
||||
/**
|
||||
* Get the number of keys in the models collection. Be aware that if there
|
||||
* are multiple object types in this collection that the count will include
|
||||
* the count of other objects in the same collection.
|
||||
*
|
||||
* @return The number of keys in the classes collection.
|
||||
*/
|
||||
+ (NSUInteger)numberOfKeysInCollection;
|
||||
+ (NSUInteger)numberOfKeysInCollectionWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
/**
|
||||
* Removes all objects in the classes collection.
|
||||
*/
|
||||
+ (void)removeAllObjectsInCollection;
|
||||
|
||||
/**
|
||||
* A memory intesive method to get all objects in the collection. You should prefer using enumeration over this method
|
||||
* whenever feasible. See `enumerateObjectsInCollectionUsingBlock`
|
||||
*
|
||||
* @return All objects in the classes collection.
|
||||
*/
|
||||
+ (NSArray *)allObjectsInCollection;
|
||||
|
||||
/**
|
||||
* Enumerates all objects in collection.
|
||||
*/
|
||||
+ (void)enumerateCollectionObjectsUsingBlock:(void (^)(id obj, BOOL *stop))block;
|
||||
+ (void)enumerateCollectionObjectsWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
usingBlock:(void (^)(id object, BOOL *stop))block;
|
||||
|
||||
/**
|
||||
* @return Shared database connections for reading and writing.
|
||||
*/
|
||||
- (YapDatabaseConnection *)dbReadConnection;
|
||||
+ (YapDatabaseConnection *)dbReadConnection;
|
||||
- (YapDatabaseConnection *)dbReadWriteConnection;
|
||||
+ (YapDatabaseConnection *)dbReadWriteConnection;
|
||||
|
||||
/**
|
||||
* Fetches the object with the provided identifier
|
||||
*
|
||||
* @param uniqueID Unique identifier of the entry in a collection
|
||||
* @param transaction Transaction used for fetching the object
|
||||
*
|
||||
* @return Instance of the object or nil if non-existent
|
||||
*/
|
||||
+ (nullable instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
NS_SWIFT_NAME(fetch(uniqueId:transaction:));
|
||||
+ (nullable instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID NS_SWIFT_NAME(fetch(uniqueId:));
|
||||
|
||||
/**
|
||||
* Saves the object with the shared readWrite connection.
|
||||
*
|
||||
* This method will block if another readWrite transaction is open.
|
||||
*/
|
||||
- (void)save;
|
||||
|
||||
/**
|
||||
* Assign the latest persisted values from the database.
|
||||
*/
|
||||
- (void)reload;
|
||||
- (void)reloadWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
- (void)reloadWithTransaction:(YapDatabaseReadTransaction *)transaction ignoreMissing:(BOOL)ignoreMissing;
|
||||
|
||||
/**
|
||||
* Saves the object with the shared readWrite connection - does not block.
|
||||
*
|
||||
* Be mindful that this method may clobber other changes persisted
|
||||
* while waiting to open the readWrite transaction.
|
||||
*
|
||||
* @param completionBlock is called on the main thread
|
||||
*/
|
||||
- (void)saveAsyncWithCompletionBlock:(void (^_Nullable)(void))completionBlock;
|
||||
|
||||
/**
|
||||
* Saves the object with the provided transaction
|
||||
*
|
||||
* @param transaction Database transaction
|
||||
*/
|
||||
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
/**
|
||||
* `touch` is a cheap way to fire a YapDatabaseModified notification to redraw anythign depending on the model.
|
||||
*/
|
||||
- (void)touch;
|
||||
- (void)touchWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
/**
|
||||
* The unique identifier of the stored object
|
||||
*/
|
||||
@property (nonatomic, nullable) NSString *uniqueId;
|
||||
|
||||
- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
- (void)remove;
|
||||
|
||||
#pragma mark - Update With...
|
||||
|
||||
// This method is used by "updateWith..." methods.
|
||||
//
|
||||
// This model may be updated from many threads. We don't want to save
|
||||
// our local copy (this instance) since it may be out of date. We also
|
||||
// want to avoid re-saving a model that has been deleted. Therefore, we
|
||||
// use "updateWith..." methods to:
|
||||
//
|
||||
// a) Update a property of this instance.
|
||||
// b) If a copy of this model exists in the database, load an up-to-date copy,
|
||||
// and update and save that copy.
|
||||
// b) If a copy of this model _DOES NOT_ exist in the database, do _NOT_ save
|
||||
// this local instance.
|
||||
//
|
||||
// After "updateWith...":
|
||||
//
|
||||
// a) Any copy of this model in the database will have been updated.
|
||||
// b) The local property on this instance will always have been updated.
|
||||
// c) Other properties on this instance may be out of date.
|
||||
//
|
||||
// All mutable properties of this class have been made read-only to
|
||||
// prevent accidentally modifying them directly.
|
||||
//
|
||||
// This isn't a perfect arrangement, but in practice this will prevent
|
||||
// data loss and will resolve all known issues.
|
||||
- (void)applyChangeToSelfAndLatestCopy:(YapDatabaseReadWriteTransaction *)transaction
|
||||
changeBlock:(void (^)(id))changeBlock;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,229 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSYapDatabaseObject.h"
|
||||
#import <YapDatabase/YapDatabaseTransaction.h>
|
||||
#import <SessionUtilitiesKit/SessionUtilitiesKit-Swift.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation TSYapDatabaseObject
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithUniqueId:[[NSUUID UUID] UUIDString]];
|
||||
}
|
||||
|
||||
- (instancetype)initWithUniqueId:(NSString *_Nullable)aUniqueId
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_uniqueId = aUniqueId;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
[transaction setObject:self forKey:self.uniqueId inCollection:[[self class] collection]];
|
||||
}
|
||||
|
||||
- (void)save
|
||||
{
|
||||
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self saveWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)saveAsyncWithCompletionBlock:(void (^_Nullable)(void))completionBlock
|
||||
{
|
||||
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self saveWithTransaction:transaction];
|
||||
} completion:completionBlock];
|
||||
}
|
||||
|
||||
- (void)touchWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
[transaction touchObjectForKey:self.uniqueId inCollection:[self.class collection]];
|
||||
}
|
||||
|
||||
- (void)touch
|
||||
{
|
||||
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self touchWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
[transaction removeObjectForKey:self.uniqueId inCollection:[[self class] collection]];
|
||||
}
|
||||
|
||||
- (void)remove
|
||||
{
|
||||
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self removeWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)dbReadConnection
|
||||
{
|
||||
return [[self class] dbReadConnection];
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)dbReadWriteConnection
|
||||
{
|
||||
return [[self class] dbReadWriteConnection];
|
||||
}
|
||||
|
||||
#pragma mark Class Methods
|
||||
|
||||
+ (MTLPropertyStorage)storageBehaviorForPropertyWithKey:(NSString *)propertyKey
|
||||
{
|
||||
if ([propertyKey isEqualToString:@"TAG"]) {
|
||||
return MTLPropertyStorageNone;
|
||||
} else {
|
||||
return [super storageBehaviorForPropertyWithKey:propertyKey];
|
||||
}
|
||||
}
|
||||
|
||||
+ (YapDatabaseConnection *)dbReadConnection
|
||||
{
|
||||
// We use TSYapDatabaseObject's dbReadWriteConnection (not OWSPrimaryStorage's
|
||||
// dbReadConnection) for consistency, since we tend to [TSYapDatabaseObject
|
||||
// save] and want to write to the same connection we read from. To get true
|
||||
// consistency, we'd want to update entities by reading & writing from within
|
||||
// the same transaction, but that'll be a big refactor.
|
||||
return self.dbReadWriteConnection;
|
||||
}
|
||||
|
||||
+ (YapDatabaseConnection *)dbReadWriteConnection
|
||||
{
|
||||
return SNUtilitiesKitConfiguration.shared.owsPrimaryStorage.dbReadWriteConnection;
|
||||
}
|
||||
|
||||
+ (NSString *)collection
|
||||
{
|
||||
return NSStringFromClass([self class]);
|
||||
}
|
||||
|
||||
+ (NSUInteger)numberOfKeysInCollection
|
||||
{
|
||||
__block NSUInteger count;
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
count = [self numberOfKeysInCollectionWithTransaction:transaction];
|
||||
}];
|
||||
return count;
|
||||
}
|
||||
|
||||
+ (NSUInteger)numberOfKeysInCollectionWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
return [transaction numberOfKeysInCollection:[self collection]];
|
||||
}
|
||||
|
||||
+ (NSArray *)allObjectsInCollection
|
||||
{
|
||||
__block NSMutableArray *all = [[NSMutableArray alloc] initWithCapacity:[self numberOfKeysInCollection]];
|
||||
[self enumerateCollectionObjectsUsingBlock:^(id object, BOOL *stop) {
|
||||
[all addObject:object];
|
||||
}];
|
||||
return [all copy];
|
||||
}
|
||||
|
||||
+ (void)enumerateCollectionObjectsUsingBlock:(void (^)(id object, BOOL *stop))block
|
||||
{
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[self enumerateCollectionObjectsWithTransaction:transaction usingBlock:block];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)enumerateCollectionObjectsWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
usingBlock:(void (^)(id object, BOOL *stop))block
|
||||
{
|
||||
// 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];
|
||||
}
|
||||
|
||||
+ (void)removeAllObjectsInCollection
|
||||
{
|
||||
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:[self collection]];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (nullable instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
return [transaction objectForKey:uniqueID inCollection:[self collection]];
|
||||
}
|
||||
|
||||
+ (nullable instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID
|
||||
{
|
||||
__block id _Nullable object = nil;
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
object = [transaction objectForKey:uniqueID inCollection:[self collection]];
|
||||
}];
|
||||
return object;
|
||||
}
|
||||
|
||||
#pragma mark - Update With...
|
||||
|
||||
- (void)applyChangeToSelfAndLatestCopy:(YapDatabaseReadWriteTransaction *)transaction
|
||||
changeBlock:(void (^)(id))changeBlock
|
||||
{
|
||||
changeBlock(self);
|
||||
|
||||
NSString *collection = [[self class] collection];
|
||||
id latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection];
|
||||
if (latestInstance) {
|
||||
changeBlock(latestInstance);
|
||||
[latestInstance saveWithTransaction:transaction];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Reload
|
||||
|
||||
- (void)reload
|
||||
{
|
||||
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[self reloadWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)reloadWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
[self reloadWithTransaction:transaction ignoreMissing:NO];
|
||||
}
|
||||
|
||||
- (void)reloadWithTransaction:(YapDatabaseReadTransaction *)transaction ignoreMissing:(BOOL)ignoreMissing
|
||||
{
|
||||
TSYapDatabaseObject *latest = [[self class] fetchObjectWithUniqueID:self.uniqueId transaction:transaction];
|
||||
if (!latest) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self setValuesForKeysWithDictionary:latest.dictionaryValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -15,7 +15,6 @@ FOUNDATION_EXPORT const unsigned char SessionUtilitiesKitVersionString[];
|
|||
#import <SessionUtilitiesKit/OWSFileSystem.h>
|
||||
#import <SessionUtilitiesKit/OWSMath.h>
|
||||
#import <SessionUtilitiesKit/TSRequest.h>
|
||||
#import <SessionUtilitiesKit/TSYapDatabaseObject.h>
|
||||
#import <SessionUtilitiesKit/UIImage+OWS.h>
|
||||
#import <SessionUtilitiesKit/UIView+OWS.h>
|
||||
|
||||
|
|
|
@ -1,20 +1,14 @@
|
|||
import SessionMessagingKit
|
||||
import SessionSnodeKit
|
||||
|
||||
extension OWSPrimaryStorage : OWSPrimaryStorageProtocol { }
|
||||
|
||||
@objc(SNConfiguration)
|
||||
public final class Configuration : NSObject {
|
||||
|
||||
|
||||
@objc public static func performMainSetup() {
|
||||
public enum Configuration {
|
||||
public static func performMainSetup() {
|
||||
// Need to do this first to ensure the legacy database exists
|
||||
SNUtilitiesKit.configure(
|
||||
owsPrimaryStorage: OWSPrimaryStorage.shared(),
|
||||
maxFileSize: UInt(Double(FileServerAPIV2.maxFileSize) / FileServerAPIV2.fileSizeORMultiplier)
|
||||
)
|
||||
|
||||
SNMessagingKit.configure(storage: Storage.shared)
|
||||
SNMessagingKit.configure()
|
||||
SNSnodeKit.configure()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,52 +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<Void>)
|
||||
}
|
||||
|
||||
func readWritePromise(_ block: @escaping (YapDatabaseReadWriteTransaction) -> Void) -> Promise<Void> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,13 +25,10 @@ public enum AppSetup {
|
|||
// All of these "singletons" should have any dependencies used in their
|
||||
// initializers injected.
|
||||
OWSBackgroundTaskManager.shared().observeNotifications()
|
||||
|
||||
let primaryStorage: OWSPrimaryStorage = OWSPrimaryStorage(storage: ())
|
||||
OWSPrimaryStorage.protectFiles()
|
||||
|
||||
|
||||
// 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
|
||||
// is NSFileProtectionComplete
|
||||
// If you receive a media message while the device is locked, the download will fail if
|
||||
// the temporary directory is NSFileProtectionComplete
|
||||
let success: Bool = OWSFileSystem.protectFileOrFolder(
|
||||
atPath: NSTemporaryDirectory(),
|
||||
fileProtectionType: .completeUntilFirstUserAuthentication
|
||||
|
@ -39,10 +36,8 @@ public enum AppSetup {
|
|||
assert(success)
|
||||
|
||||
Environment.shared = Environment(
|
||||
primaryStorage: primaryStorage,
|
||||
reachabilityManager: SSKReachabilityManagerImpl(),
|
||||
audioSession: OWSAudioSession(),
|
||||
preferences: OWSPreferences(),
|
||||
proximityMonitoringManager: OWSProximityMonitoringManagerImpl(),
|
||||
windowManager: OWSWindowManager(default: ())
|
||||
)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import SessionUtilitiesKit
|
||||
|
||||
@objc public class OWSAlerts: NSObject {
|
||||
|
||||
|
@ -93,32 +94,4 @@ import Foundation
|
|||
action.accessibilityIdentifier = "OWSAlerts.\("cancel")"
|
||||
return action
|
||||
}
|
||||
|
||||
@objc
|
||||
public class func showIOSUpgradeNagIfNecessary() {
|
||||
// Our min SDK is iOS9, so this will only show for iOS9 users
|
||||
if #available(iOS 10.0, *) {
|
||||
return
|
||||
}
|
||||
|
||||
// Don't show the nag to users who have just launched
|
||||
// the app for the first time.
|
||||
guard AppVersion.sharedInstance().lastAppVersion != nil else {
|
||||
return
|
||||
}
|
||||
|
||||
if let iOSUpgradeNagDate = Environment.shared.preferences.iOSUpgradeNagDate() {
|
||||
let kNagFrequencySeconds = 14 * kDayInterval
|
||||
guard fabs(iOSUpgradeNagDate.timeIntervalSinceNow) > kNagFrequencySeconds else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Environment.shared.preferences.setIOSUpgradeNagDate(Date())
|
||||
|
||||
OWSAlerts.showAlert(title: NSLocalizedString("UPGRADE_IOS_ALERT_TITLE",
|
||||
comment: "Title for the alert indicating that user should upgrade iOS."),
|
||||
message: NSLocalizedString("UPGRADE_IOS_ALERT_MESSAGE",
|
||||
comment: "Message for the alert indicating that user should upgrade iOS."))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue