diff --git a/SessionMessagingKit/Database/OWSPrimaryStorage.m b/SessionMessagingKit/Database/OWSPrimaryStorage.m index e5063e686..d1fc7c22f 100644 --- a/SessionMessagingKit/Database/OWSPrimaryStorage.m +++ b/SessionMessagingKit/Database/OWSPrimaryStorage.m @@ -179,7 +179,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) [OWSDisappearingMessagesFinder asyncRegisterDatabaseExtensions:self]; [OWSMediaGalleryFinder asyncRegisterDatabaseExtensionsWithPrimaryStorage:self]; [TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:self]; - [SSKJobRecordFinder asyncRegisterDatabaseExtensionObjCWithStorage:self]; [self.database flushExtensionRequestsWithCompletionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) diff --git a/SessionMessagingKit/Meta/SessionMessagingKit.h b/SessionMessagingKit/Meta/SessionMessagingKit.h index ca96b4f92..1033e2d6d 100644 --- a/SessionMessagingKit/Meta/SessionMessagingKit.h +++ b/SessionMessagingKit/Meta/SessionMessagingKit.h @@ -34,7 +34,6 @@ FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[]; #import #import #import -#import #import #import #import diff --git a/SessionMessagingKit/Utilities/SSKJobRecord.h b/SessionMessagingKit/Utilities/SSKJobRecord.h deleted file mode 100644 index 30c4adf2b..000000000 --- a/SessionMessagingKit/Utilities/SSKJobRecord.h +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -extern NSErrorDomain const SSKJobRecordErrorDomain; - -typedef NS_ERROR_ENUM(SSKJobRecordErrorDomain, JobRecordError){ - JobRecordError_AssertionError = 100, - JobRecordError_IllegalStateTransition, -}; - -typedef NS_ENUM(NSUInteger, SSKJobRecordStatus) { - SSKJobRecordStatus_Unknown, - SSKJobRecordStatus_Ready, - SSKJobRecordStatus_Running, - SSKJobRecordStatus_PermanentlyFailed, - SSKJobRecordStatus_Obsolete -}; - -#pragma mark - - -@interface SSKJobRecord : TSYapDatabaseObject - -@property (nonatomic) NSUInteger failureCount; -@property (nonatomic) NSString *label; - -- (instancetype)initWithLabel:(NSString *)label NS_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - -- (instancetype)initWithUniqueId:(NSString *_Nullable)uniqueId NS_UNAVAILABLE; -- (instancetype)init NS_UNAVAILABLE; - -@property (readonly, nonatomic) SSKJobRecordStatus status; -@property (nonatomic, readonly) UInt64 sortId; - -- (BOOL)saveAsStartedWithTransaction:(YapDatabaseReadWriteTransaction *)transaction - error:(NSError **)outError NS_SWIFT_NAME(saveAsStarted(transaction:)); - -- (void)saveAsPermanentlyFailedWithTransaction:(YapDatabaseReadWriteTransaction *)transaction - NS_SWIFT_NAME(saveAsPermanentlyFailed(transaction:)); - -- (void)saveAsObsoleteWithTransaction:(YapDatabaseReadWriteTransaction *)transaction - NS_SWIFT_NAME(saveAsObsolete(transaction:)); - -- (BOOL)saveRunningAsReadyWithTransaction:(YapDatabaseReadWriteTransaction *)transaction - error:(NSError **)outError NS_SWIFT_NAME(saveRunningAsReady(transaction:)); - -- (BOOL)addFailureWithWithTransaction:(YapDatabaseReadWriteTransaction *)transaction - error:(NSError **)outError NS_SWIFT_NAME(addFailure(transaction:)); - -@end - -NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Utilities/SSKJobRecord.m b/SessionMessagingKit/Utilities/SSKJobRecord.m deleted file mode 100644 index 71ef09139..000000000 --- a/SessionMessagingKit/Utilities/SSKJobRecord.m +++ /dev/null @@ -1,127 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "SSKJobRecord.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -NSErrorDomain const SSKJobRecordErrorDomain = @"SignalServiceKit.JobRecord"; - -#pragma mark - -@interface SSKJobRecord () - -@property (nonatomic) SSKJobRecordStatus status; -@property (nonatomic) UInt64 sortId; - -@end - -@implementation SSKJobRecord - -- (instancetype)initWithLabel:(NSString *)label -{ - self = [super init]; - if (!self) { - return self; - } - - _status = SSKJobRecordStatus_Ready; - _label = label; - - return self; -} - -- (nullable instancetype)initWithCoder:(NSCoder *)coder -{ - return [super initWithCoder:coder]; -} - -#pragma mark - TSYapDatabaseObject Overrides - -+ (NSString *)collection -{ - // To avoid a plethora of identical JobRecord subclasses, all job records share - // a common collection and JobQueue's distinguish their behavior by the job's - // `label` - return @"JobRecord"; -} - -- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (self.sortId == 0) { - self.sortId = [SSKIncrementingIdFinder nextIdWithKey:self.class.collection transaction:transaction]; - } - [super saveWithTransaction:transaction]; -} - -#pragma mark - - -- (BOOL)saveAsStartedWithTransaction:(YapDatabaseReadWriteTransaction *)transaction error:(NSError **)outError -{ - if (self.status != SSKJobRecordStatus_Ready) { - *outError = - [NSError errorWithDomain:SSKJobRecordErrorDomain code:JobRecordError_IllegalStateTransition userInfo:nil]; - return NO; - } - self.status = SSKJobRecordStatus_Running; - [self saveWithTransaction:transaction]; - - return YES; -} - -- (void)saveAsPermanentlyFailedWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - self.status = SSKJobRecordStatus_PermanentlyFailed; - [self saveWithTransaction:transaction]; -} - -- (void)saveAsObsoleteWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - self.status = SSKJobRecordStatus_Obsolete; - [self saveWithTransaction:transaction]; -} - -- (BOOL)saveRunningAsReadyWithTransaction:(YapDatabaseReadWriteTransaction *)transaction error:(NSError **)outError -{ - switch (self.status) { - case SSKJobRecordStatus_Running: { - self.status = SSKJobRecordStatus_Ready; - [self saveWithTransaction:transaction]; - return YES; - } - case SSKJobRecordStatus_Ready: - case SSKJobRecordStatus_PermanentlyFailed: - case SSKJobRecordStatus_Obsolete: - case SSKJobRecordStatus_Unknown: { - *outError = [NSError errorWithDomain:SSKJobRecordErrorDomain - code:JobRecordError_IllegalStateTransition - userInfo:nil]; - return NO; - } - } -} - -- (BOOL)addFailureWithWithTransaction:(YapDatabaseReadWriteTransaction *)transaction error:(NSError **)outError -{ - switch (self.status) { - case SSKJobRecordStatus_Running: { - self.failureCount++; - [self saveWithTransaction:transaction]; - return YES; - } - case SSKJobRecordStatus_Ready: - case SSKJobRecordStatus_PermanentlyFailed: - case SSKJobRecordStatus_Obsolete: - case SSKJobRecordStatus_Unknown: { - *outError = [NSError errorWithDomain:SSKJobRecordErrorDomain - code:JobRecordError_IllegalStateTransition - userInfo:nil]; - return NO; - } - } -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Utilities/SSKJobRecordFinder.swift b/SessionMessagingKit/Utilities/SSKJobRecordFinder.swift deleted file mode 100644 index 8b633019a..000000000 --- a/SessionMessagingKit/Utilities/SSKJobRecordFinder.swift +++ /dev/null @@ -1,108 +0,0 @@ - -@objc(SSKJobRecordFinder) -public class JobRecordFinder: NSObject, Finder { - - public typealias ExtensionType = YapDatabaseSecondaryIndex - public typealias TransactionType = YapDatabaseSecondaryIndexTransaction - - public enum JobRecordField: String { - case status, label, sortId - } - - public func getNextReady(label: String, transaction: YapDatabaseReadTransaction) -> SSKJobRecord? { - var result: SSKJobRecord? - self.enumerateJobRecords(label: label, status: .ready, transaction: transaction) { jobRecord, stopPointer in - result = jobRecord - stopPointer.pointee = true - } - return result - } - - public func allRecords(label: String, status: SSKJobRecordStatus, transaction: YapDatabaseReadTransaction) -> [SSKJobRecord] { - var result: [SSKJobRecord] = [] - self.enumerateJobRecords(label: label, status: status, transaction: transaction) { jobRecord, _ in - result.append(jobRecord) - } - return result - } - - public func enumerateJobRecords(label: String, status: SSKJobRecordStatus, transaction: YapDatabaseReadTransaction, block: @escaping (SSKJobRecord, UnsafeMutablePointer) -> Void) { - let queryFormat = String(format: "WHERE %@ = ? AND %@ = ? ORDER BY %@", JobRecordField.status.rawValue, JobRecordField.label.rawValue, JobRecordField.sortId.rawValue) - let query = YapDatabaseQuery(string: queryFormat, parameters: [status.rawValue, label]) - - self.ext(transaction: transaction).enumerateKeysAndObjects(matching: query) { _, _, object, stopPointer in - guard let jobRecord = object as? SSKJobRecord else { - owsFailDebug("expecting jobRecord but found: \(object)") - return - } - block(jobRecord, stopPointer) - } - } - - public static var dbExtensionName: String { - return "SecondaryIndexJobRecord" - } - - @objc - public class func asyncRegisterDatabaseExtensionObjC(storage: OWSStorage) { - asyncRegisterDatabaseExtension(storage: storage) - } - - public static var dbExtensionConfig: YapDatabaseSecondaryIndex { - let setup = YapDatabaseSecondaryIndexSetup() - setup.addColumn(JobRecordField.sortId.rawValue, with: .integer) - setup.addColumn(JobRecordField.status.rawValue, with: .integer) - setup.addColumn(JobRecordField.label.rawValue, with: .text) - - let block: YapDatabaseSecondaryIndexWithObjectBlock = { transaction, dict, collection, key, object in - guard let jobRecord = object as? SSKJobRecord else { - return - } - - dict[JobRecordField.sortId.rawValue] = jobRecord.sortId - dict[JobRecordField.status.rawValue] = jobRecord.status.rawValue - dict[JobRecordField.label.rawValue] = jobRecord.label - } - - let handler = YapDatabaseSecondaryIndexHandler.withObjectBlock(block) - - let options = YapDatabaseSecondaryIndexOptions() - let whitelist = YapWhitelistBlacklist(whitelist: Set([SSKJobRecord.collection()])) - options.allowedCollections = whitelist - - return YapDatabaseSecondaryIndex.init(setup: setup, handler: handler, versionTag: "2", options: options) - } -} - -protocol Finder { - associatedtype ExtensionType: YapDatabaseExtension - associatedtype TransactionType: YapDatabaseExtensionTransaction - - static var dbExtensionName: String { get } - static var dbExtensionConfig: ExtensionType { get } - - func ext(transaction: YapDatabaseReadTransaction) -> TransactionType - - static func asyncRegisterDatabaseExtension(storage: OWSStorage) - static func testingOnly_ensureDatabaseExtensionRegistered(storage: OWSStorage) -} - -extension Finder { - - public func ext(transaction: YapDatabaseReadTransaction) -> TransactionType { - return transaction.ext(type(of: self).dbExtensionName) as! TransactionType - } - - public static func asyncRegisterDatabaseExtension(storage: OWSStorage) { - storage.asyncRegister(dbExtensionConfig, withName: dbExtensionName) - } - - // Only for testing. - public static func testingOnly_ensureDatabaseExtensionRegistered(storage: OWSStorage) { - guard storage.registeredExtension(dbExtensionName) == nil else { - return - } - - storage.register(dbExtensionConfig, withName: dbExtensionName) - } -} diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index d634abd66..40acf58bd 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -489,7 +489,6 @@ C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB69255A580F00E217F9 /* FeatureFlags.swift */; }; C33FDD32255A582000E217F9 /* OWSOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB78255A581000E217F9 /* OWSOperation.m */; }; C33FDD3A255A582000E217F9 /* Notification+Loki.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB80255A581100E217F9 /* Notification+Loki.swift */; }; - C33FDD41255A582000E217F9 /* JobQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB87255A581100E217F9 /* JobQueue.swift */; }; C33FDD45255A582000E217F9 /* Storage+SessionManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */; }; C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8F255A581200E217F9 /* ParamParser.swift */; }; C33FDD53255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */; }; @@ -686,9 +685,6 @@ C396DAF42518408B00FF6DC5 /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C396DAED2518408B00FF6DC5 /* Parser.swift */; }; C396DAF52518408B00FF6DC5 /* CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = C396DAEE2518408B00FF6DC5 /* CSV.swift */; }; C3A3A08F256E1728004D228D /* FullTextSearchFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */; }; - C3A3A099256E17B2004D228D /* SSKJobRecordFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A3A098256E17B2004D228D /* SSKJobRecordFinder.swift */; }; - C3A3A0AA256E17E6004D228D /* SSKJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACD255A580200E217F9 /* SSKJobRecord.m */; }; - C3A3A0B3256E17F2004D228D /* SSKJobRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */; settings = {ATTRIBUTES = (Public, ); }; }; C3A3A0EC256E1949004D228D /* OWSRecipientIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */; }; C3A3A0F5256E194C004D228D /* OWSRecipientIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */; settings = {ATTRIBUTES = (Public, ); }; }; C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */; }; @@ -1379,7 +1375,6 @@ C33FDAC2255A580200E217F9 /* TSAttachment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachment.m; sourceTree = ""; }; C33FDAC3255A580200E217F9 /* OWSDispatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDispatch.m; sourceTree = ""; }; C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentStream.m; sourceTree = ""; }; - C33FDACD255A580200E217F9 /* SSKJobRecord.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSKJobRecord.m; sourceTree = ""; }; C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAttachmentDownloads.h; sourceTree = ""; }; C33FDAD3255A580300E217F9 /* TSThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSThread.h; sourceTree = ""; }; C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSQuotedMessage.h; sourceTree = ""; }; @@ -1438,7 +1433,6 @@ C33FDB48255A580C00E217F9 /* TSOutgoingMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSOutgoingMessage.h; sourceTree = ""; }; C33FDB49255A580C00E217F9 /* WeakTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakTimer.swift; sourceTree = ""; }; C33FDB4C255A580D00E217F9 /* AppVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppVersion.h; sourceTree = ""; }; - C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKJobRecord.h; sourceTree = ""; }; C33FDB51255A580D00E217F9 /* NSUserDefaults+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSUserDefaults+OWS.h"; sourceTree = ""; }; C33FDB54255A580D00E217F9 /* DataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataSource.h; sourceTree = ""; }; C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSOutgoingMessage.m; sourceTree = ""; }; @@ -1466,7 +1460,6 @@ C33FDB81255A581100E217F9 /* UIImage+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+OWS.m"; sourceTree = ""; }; C33FDB83255A581100E217F9 /* TSQuotedMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSQuotedMessage.m; sourceTree = ""; }; C33FDB85255A581100E217F9 /* AppContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppContext.m; sourceTree = ""; }; - C33FDB87255A581100E217F9 /* JobQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JobQueue.swift; sourceTree = ""; }; C33FDB88255A581200E217F9 /* TSAccountManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAccountManager.m; sourceTree = ""; }; C33FDB8A255A581200E217F9 /* AppContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppContext.h; sourceTree = ""; }; C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+SessionManagement.swift"; sourceTree = ""; }; @@ -1721,7 +1714,6 @@ C396DAED2518408B00FF6DC5 /* Parser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = ""; }; C396DAEE2518408B00FF6DC5 /* CSV.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSV.swift; sourceTree = ""; }; C39DD28724F3318C008590FC /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = ""; }; - C3A3A098256E17B2004D228D /* SSKJobRecordFinder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSKJobRecordFinder.swift; sourceTree = ""; }; C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSKReachabilityManager.swift; sourceTree = ""; }; C3A71D0A2558989C0043A11F /* MessageWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageWrapper.swift; sourceTree = ""; }; C3A71D1C25589AC30043A11F /* WebSocketProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketProto.swift; sourceTree = ""; }; @@ -2875,7 +2867,6 @@ C38EF286255B6D85007E1867 /* VersionMigrations.m */, C33FDA8B255A57FD00E217F9 /* AppVersion.m */, C33FDB69255A580F00E217F9 /* FeatureFlags.swift */, - C33FDB87255A581100E217F9 /* JobQueue.swift */, C33FDA99255A57FE00E217F9 /* OutageDetection.swift */, C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */, C33FDC13255A581E00E217F9 /* OWSAttachmentDownloads.m */, @@ -3189,9 +3180,6 @@ C33FDB31255A580A00E217F9 /* SSKEnvironment.h */, C33FDAF4255A580600E217F9 /* SSKEnvironment.m */, C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */, - C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */, - C33FDACD255A580200E217F9 /* SSKJobRecord.m */, - C3A3A098256E17B2004D228D /* SSKJobRecordFinder.swift */, C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */, C3ECBF7A257056B700EA7FCE /* Threading.swift */, C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */, @@ -3664,7 +3652,6 @@ C32C5ADF256DBFAA003C73A2 /* OWSReadTracking.h in Headers */, C3D9E486256775D20040E4F3 /* TSAttachmentPointer.h in Headers */, C32C5EF7256DF567003C73A2 /* TSDatabaseView.h in Headers */, - C3A3A0B3256E17F2004D228D /* SSKJobRecord.h in Headers */, B8856ED7256F1EB4001CE70E /* OWSPreferences.h in Headers */, C32A026C25A801AF000ED5D4 /* NSData+messagePadding.h in Headers */, C32C5BE6256DC891003C73A2 /* OWSReadReceiptManager.h in Headers */, @@ -4619,7 +4606,6 @@ C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */, C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */, B8B3204E258C15C80020074B /* ContactsMigration.swift in Sources */, - C33FDD41255A582000E217F9 /* JobQueue.swift in Sources */, C32A025A25A7FC55000ED5D4 /* ClosedGroupsV2Migration.swift in Sources */, C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */, C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */, @@ -4790,7 +4776,6 @@ C32C5D9C256DD6DC003C73A2 /* OWSOutgoingReceiptManager.m in Sources */, C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */, B8B3207B258C22550020074B /* DisplayNameUtilities.swift in Sources */, - C3A3A099256E17B2004D228D /* SSKJobRecordFinder.swift in Sources */, B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */, C32C5EDC256DF501003C73A2 /* YapDatabaseConnection+OWS.m in Sources */, C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */, @@ -4854,7 +4839,6 @@ C352A2F525574B4700338F3E /* Job.swift in Sources */, C32C5C01256DC9A0003C73A2 /* OWSIdentityManager.m in Sources */, C32C59C4256DB41F003C73A2 /* TSContactThread.m in Sources */, - C3A3A0AA256E17E6004D228D /* SSKJobRecord.m in Sources */, C32C5AB0256DBE8F003C73A2 /* TSOutgoingMessage.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/SignalUtilitiesKit/JobQueue.swift b/SignalUtilitiesKit/JobQueue.swift deleted file mode 100644 index 7c4f90f92..000000000 --- a/SignalUtilitiesKit/JobQueue.swift +++ /dev/null @@ -1,303 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - -/// JobQueue - A durable work queue -/// -/// When work needs to be done, add it to the JobQueue. -/// The JobQueue will persist a JobRecord to be sure that work can be restarted if the app is killed. -/// -/// The actual work, is carried out in a DurableOperation which the JobQueue spins off, based on the contents -/// of a JobRecord. -/// -/// For a concrete example, take message sending. -/// Add an outgoing message to the MessageSenderJobQueue, which first records a SSKMessageSenderJobRecord. -/// The MessageSenderJobQueue then uses that SSKMessageSenderJobRecord to create a MessageSenderOperation which -/// takes care of the actual business of communicating with the service. -/// -/// DurableOperations are retryable - via their `remainingRetries` logic. However, if the operation encounters -/// an error where `error.isRetryable == false`, the operation will fail, regardless of available retries. - -public extension Error { - var isRetryable: Bool { - return (self as NSError).isRetryable - } -} - -extension SSKJobRecordStatus: CustomStringConvertible { - public var description: String { - switch self { - case .ready: - return "ready" - case .unknown: - return "unknown" - case .running: - return "running" - case .permanentlyFailed: - return "permanentlyFailed" - case .obsolete: - return "obsolete" - } - } -} - -public enum JobError: Error { - case assertionFailure(description: String) - case obsolete(description: String) -} - -public protocol DurableOperation: class { - associatedtype JobRecordType: SSKJobRecord - associatedtype DurableOperationDelegateType: DurableOperationDelegate - - var jobRecord: JobRecordType { get } - var durableOperationDelegate: DurableOperationDelegateType? { get set } - var operation: OWSOperation { get } - var remainingRetries: UInt { get set } -} - -public protocol DurableOperationDelegate: class { - associatedtype DurableOperationType: DurableOperation - - func durableOperationDidSucceed(_ operation: DurableOperationType, transaction: YapDatabaseReadWriteTransaction) - func durableOperation(_ operation: DurableOperationType, didReportError: Error, transaction: YapDatabaseReadWriteTransaction) - func durableOperation(_ operation: DurableOperationType, didFailWithError error: Error, transaction: YapDatabaseReadWriteTransaction) -} - -public protocol JobQueue: DurableOperationDelegate { - typealias DurableOperationDelegateType = Self - typealias JobRecordType = DurableOperationType.JobRecordType - - // MARK: Dependencies - - var dbConnection: YapDatabaseConnection { get } - var finder: JobRecordFinder { get } - - // MARK: Default Implementations - - func add(jobRecord: JobRecordType, transaction: YapDatabaseReadWriteTransaction) - func restartOldJobs() - func workStep() - func defaultSetup() - - // MARK: Required - - var runningOperations: [DurableOperationType] { get set } - var jobRecordLabel: String { get } - - var isSetup: Bool { get set } - func setup() - func didMarkAsReady(oldJobRecord: JobRecordType, transaction: YapDatabaseReadWriteTransaction) - - func operationQueue(jobRecord: JobRecordType) -> OperationQueue - func buildOperation(jobRecord: JobRecordType, transaction: YapDatabaseReadTransaction) throws -> DurableOperationType - - /// When `requiresInternet` is true, we immediately run any jobs which are waiting for retry upon detecting Reachability. - /// - /// Because `Reachability` isn't 100% reliable, the jobs will be attempted regardless of what we think our current Reachability is. - /// However, because these jobs will likely fail many times in succession, their `retryInterval` could be quite long by the time we - /// are back online. - var requiresInternet: Bool { get } - static var maxRetries: UInt { get } -} - -public extension JobQueue { - - // MARK: Dependencies - - var dbConnection: YapDatabaseConnection { - return SSKEnvironment.shared.primaryStorage.dbReadWriteConnection - } - - var finder: JobRecordFinder { - return JobRecordFinder() - } - - var reachabilityManager: SSKReachabilityManager { - return SSKEnvironment.shared.reachabilityManager - } - - // MARK: - - func add(jobRecord: JobRecordType, transaction: YapDatabaseReadWriteTransaction) { - assert(jobRecord.status == .ready) - - jobRecord.save(with: transaction) - - transaction.addCompletionQueue(DispatchQueue.global()) { - self.startWorkWhenAppIsReady() - } - } - - func startWorkWhenAppIsReady() { - guard !CurrentAppContext().isRunningTests else { - DispatchQueue.global().async { - self.workStep() - } - return - } - - AppReadiness.runNowOrWhenAppDidBecomeReady { - DispatchQueue.global().async { - self.workStep() - } - } - } - - func workStep() { - Logger.debug("") - - guard isSetup else { - if !CurrentAppContext().isRunningTests { - owsFailDebug("not setup") - } - - return - } - - Storage.writeSync { transaction in - guard let nextJob: JobRecordType = self.finder.getNextReady(label: self.jobRecordLabel, transaction: transaction) as? JobRecordType else { - Logger.verbose("nothing left to enqueue") - return - } - - do { - try nextJob.saveAsStarted(transaction: transaction) - - let operationQueue = self.operationQueue(jobRecord: nextJob) - let durableOperation = try self.buildOperation(jobRecord: nextJob, transaction: transaction) - - durableOperation.durableOperationDelegate = self as? Self.DurableOperationType.DurableOperationDelegateType - assert(durableOperation.durableOperationDelegate != nil) - - let remainingRetries = self.remainingRetries(durableOperation: durableOperation) - durableOperation.remainingRetries = remainingRetries - - self.runningOperations.append(durableOperation) - - Logger.debug("adding operation: \(durableOperation) with remainingRetries: \(remainingRetries)") - operationQueue.addOperation(durableOperation.operation) - } catch JobError.assertionFailure(let description) { - owsFailDebug("assertion failure: \(description)") - nextJob.saveAsPermanentlyFailed(transaction: transaction) - } catch JobError.obsolete(let description) { - // TODO is this even worthwhile to have obsolete state? Should we just delete the task outright? - Logger.verbose("marking obsolete task as such. description:\(description)") - nextJob.saveAsObsolete(transaction: transaction) - } catch { - owsFailDebug("unexpected error") - } - - DispatchQueue.global().async { - self.workStep() - } - } - } - - public func restartOldJobs() { - Storage.writeSync { transaction in - let runningRecords = self.finder.allRecords(label: self.jobRecordLabel, status: .running, transaction: transaction) - Logger.info("marking old `running` JobRecords as ready: \(runningRecords.count)") - for record in runningRecords { - guard let jobRecord = record as? JobRecordType else { - owsFailDebug("unexpectred jobRecord: \(record)") - continue - } - do { - try jobRecord.saveRunningAsReady(transaction: transaction) - self.didMarkAsReady(oldJobRecord: jobRecord, transaction: transaction) - } catch { - owsFailDebug("failed to mark old running records as ready error: \(error)") - jobRecord.saveAsPermanentlyFailed(transaction: transaction) - } - } - } - } - - /// Unless you need special handling, your setup method can be as simple as - /// - /// func setup() { - /// defaultSetup() - /// } - /// - /// So you might ask, why not just rename this method to `setup`? Because - /// `setup` is called from objc, and default implementations from a protocol - /// cannot be marked as @objc. - func defaultSetup() { - guard !isSetup else { - owsFailDebug("already ready already") - return - } - self.restartOldJobs() - - if self.requiresInternet { - NotificationCenter.default.addObserver(forName: .reachabilityChanged, - object: self.reachabilityManager.observationContext, - queue: nil) { _ in - - if self.reachabilityManager.isReachable { - Logger.verbose("isReachable: true") - self.becameReachable() - } else { - Logger.verbose("isReachable: false") - } - } - } - - self.isSetup = true - - self.startWorkWhenAppIsReady() - } - - func remainingRetries(durableOperation: DurableOperationType) -> UInt { - let maxRetries = type(of: self).maxRetries - let failureCount = durableOperation.jobRecord.failureCount - - guard maxRetries > failureCount else { - return 0 - } - - return maxRetries - failureCount - } - - func becameReachable() { - guard requiresInternet else { - owsFailDebug("should only be called if `requiresInternet` is true") - return - } - - _ = self.runAnyQueuedRetry() - } - - func runAnyQueuedRetry() -> DurableOperationType? { - guard let runningDurableOperation = self.runningOperations.first else { - return nil - } - runningDurableOperation.operation.runAnyQueuedRetry() - - return runningDurableOperation - } - - // MARK: DurableOperationDelegate - - func durableOperationDidSucceed(_ operation: DurableOperationType, transaction: YapDatabaseReadWriteTransaction) { - self.runningOperations = self.runningOperations.filter { $0 !== operation } - operation.jobRecord.remove(with: transaction) - } - - func durableOperation(_ operation: DurableOperationType, didReportError: Error, transaction: YapDatabaseReadWriteTransaction) { - do { - try operation.jobRecord.addFailure(transaction: transaction) - } catch { - owsFailDebug("error while addingFailure: \(error)") - operation.jobRecord.saveAsPermanentlyFailed(transaction: transaction) - } - } - - func durableOperation(_ operation: DurableOperationType, didFailWithError error: Error, transaction: YapDatabaseReadWriteTransaction) { - self.runningOperations = self.runningOperations.filter { $0 !== operation } - operation.jobRecord.saveAsPermanentlyFailed(transaction: transaction) - } -}