mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Further work on the JobRunner
Moved the JobRunner into SessionUtilitiesKit so it can be used by SessionSnodeKit Exposed a 'sharedLokiProject' value on UserDefaults to remove the hard-coded group name used everywhere Added "blocking" job support for 'OnLaunch' and 'OnActive' jobs to the JobRunner (will retry until it succeeds) Added the UpdateProfilePicture and RetrieveDefaultOpenGroupRooms jobs
This commit is contained in:
parent
94742c80ec
commit
3baeb981d9
|
@ -33,6 +33,8 @@ public enum SNMessagingKit { // Just to make the external API nice
|
|||
JobRunner.add(executor: DisappearingMessagesJob.self, for: .disappearingMessages)
|
||||
JobRunner.add(executor: FailedMessagesJob.self, for: .failedMessages)
|
||||
JobRunner.add(executor: FailedAttachmentDownloadsJob.self, for: .failedAttachmentDownloads)
|
||||
JobRunner.add(executor: UpdateProfilePictureJob.self, for: .updateProfilePicture)
|
||||
JobRunner.add(executor: RetrieveDefaultOpenGroupRoomsJob.self, for: .retrieveDefaultOpenGroupRooms)
|
||||
JobRunner.add(executor: MessageSendJob.self, for: .messageSend)
|
||||
JobRunner.add(executor: MessageReceiveJob.self, for: .messageReceive)
|
||||
JobRunner.add(executor: NotifyPushServerJob.self, for: .notifyPushServer)
|
|
@ -751,7 +751,7 @@
|
|||
FD17D7A027F40CC800122BE0 /* _001_InitialSetupMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D79F27F40CC800122BE0 /* _001_InitialSetupMigration.swift */; };
|
||||
FD17D7A127F40D2500122BE0 /* GRDBStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD28A4F527EAD44C00FF65E7 /* GRDBStorage.swift */; };
|
||||
FD17D7A227F40F0500122BE0 /* _001_InitialSetupMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D79527F3E04600122BE0 /* _001_InitialSetupMigration.swift */; };
|
||||
FD17D7A427F40F8100122BE0 /* _002_YDBToGRDBMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D7A327F40F8100122BE0 /* _002_YDBToGRDBMigration.swift */; };
|
||||
FD17D7A427F40F8100122BE0 /* _003_YDBToGRDBMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D7A327F40F8100122BE0 /* _003_YDBToGRDBMigration.swift */; };
|
||||
FD17D7A727F41AF000122BE0 /* SSKLegacyModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D7A627F41AF000122BE0 /* SSKLegacyModels.swift */; };
|
||||
FD17D7AA27F41BF500122BE0 /* SnodeSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D7A927F41BF500122BE0 /* SnodeSet.swift */; };
|
||||
FD17D7AE27F41C4300122BE0 /* SnodeReceivedMessageInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D7AD27F41C4300122BE0 /* SnodeReceivedMessageInfo.swift */; };
|
||||
|
@ -772,7 +772,7 @@
|
|||
FD17D7D827F658E200122BE0 /* SSKDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D7D727F658E200122BE0 /* SSKDestination.swift */; };
|
||||
FD17D7E127F67BD400122BE0 /* SnodeReceivedMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D7E027F67BD400122BE0 /* SnodeReceivedMessage.swift */; };
|
||||
FD17D7E527F6A09900122BE0 /* Identity.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D7E427F6A09900122BE0 /* Identity.swift */; };
|
||||
FD17D7E727F6A16700122BE0 /* _002_YDBToGRDBMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D7E627F6A16700122BE0 /* _002_YDBToGRDBMigration.swift */; };
|
||||
FD17D7E727F6A16700122BE0 /* _003_YDBToGRDBMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D7E627F6A16700122BE0 /* _003_YDBToGRDBMigration.swift */; };
|
||||
FD17D7EA27F6A1C600122BE0 /* SUKLegacyModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD17D7E927F6A1C600122BE0 /* SUKLegacyModels.swift */; };
|
||||
FD28A4F227E990E800FF65E7 /* BlockingManagerRemovalMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD28A4F127E990E800FF65E7 /* BlockingManagerRemovalMigration.swift */; };
|
||||
FD28A4F427EA79F800FF65E7 /* BlockListUIUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */; };
|
||||
|
@ -781,6 +781,9 @@
|
|||
FD5D200F27AA2B6000FEA984 /* MessageRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D200E27AA2B6000FEA984 /* MessageRequestResponse.swift */; };
|
||||
FD5D201127AA331F00FEA984 /* ConfigurationMessage+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D201027AA331F00FEA984 /* ConfigurationMessage+Convenience.swift */; };
|
||||
FD659AC027A7649600F12C02 /* MessageRequestsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD659ABF27A7649600F12C02 /* MessageRequestsViewController.swift */; };
|
||||
FD6A7A692818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6A7A682818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift */; };
|
||||
FD6A7A6B2818C17C00035AC1 /* UpdateProfilePictureJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6A7A6A2818C17C00035AC1 /* UpdateProfilePictureJob.swift */; };
|
||||
FD6A7A6D2818C61500035AC1 /* _002_SetupStandardJobs.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6A7A6C2818C61500035AC1 /* _002_SetupStandardJobs.swift */; };
|
||||
FD705A8C278CDB5600F16121 /* SAEScreenLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8B278CDB5600F16121 /* SAEScreenLockViewController.swift */; };
|
||||
FD705A8E278CE29800F16121 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8D278CE29800F16121 /* String+Localization.swift */; };
|
||||
FD705A90278CEBBC00F16121 /* ShareAppExtensionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8F278CEBBC00F16121 /* ShareAppExtensionContext.swift */; };
|
||||
|
@ -790,6 +793,11 @@
|
|||
FD859F0027C4691300510D0C /* MockDataGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD859EFF27C4691300510D0C /* MockDataGenerator.swift */; };
|
||||
FD88BAD927A7439C00BBC442 /* MessageRequestsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */; };
|
||||
FD88BADB27A750F200BBC442 /* MessageRequestsMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */; };
|
||||
FD90040F2818AB6D00ABAAF6 /* GetSnodePoolJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD90040E2818AB6D00ABAAF6 /* GetSnodePoolJob.swift */; };
|
||||
FD9004122818ABDC00ABAAF6 /* Job.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B73F280402C4004C14C5 /* Job.swift */; };
|
||||
FD9004142818AD0B00ABAAF6 /* _002_SetupStandardJobs.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9004132818AD0B00ABAAF6 /* _002_SetupStandardJobs.swift */; };
|
||||
FD9004152818B46300ABAAF6 /* JobRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7432804EF1B004C14C5 /* JobRunner.swift */; };
|
||||
FD9004162818B46700ABAAF6 /* JobRunnerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE77F68280F9EDA002CFC5D /* JobRunnerError.swift */; };
|
||||
FDA8EAFE280E8B78002B68E5 /* FailedMessagesJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDA8EAFD280E8B78002B68E5 /* FailedMessagesJob.swift */; };
|
||||
FDA8EB00280E8D58002B68E5 /* FailedAttachmentDownloadsJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDA8EAFF280E8D58002B68E5 /* FailedAttachmentDownloadsJob.swift */; };
|
||||
FDA8EB09280E90FB002B68E5 /* AppSetup.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF287255B6D85007E1867 /* AppSetup.m */; };
|
||||
|
@ -798,12 +806,9 @@
|
|||
FDC4389E27BA2B8A00C60D73 /* SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */; };
|
||||
FDCDB8DE2810F73B00352A0C /* Differentiable+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDCDB8DD2810F73B00352A0C /* Differentiable+Utilities.swift */; };
|
||||
FDCDB8E02811007F00352A0C /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDCDB8DF2811007F00352A0C /* HomeViewModel.swift */; };
|
||||
FDE77F69280F9EDA002CFC5D /* JobRunnerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE77F68280F9EDA002CFC5D /* JobRunnerError.swift */; };
|
||||
FDE77F6B280FEB28002CFC5D /* ControlMessageProcessRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE77F6A280FEB28002CFC5D /* ControlMessageProcessRecord.swift */; };
|
||||
FDF0B73C27FFD3D6004C14C5 /* LinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B73B27FFD3D6004C14C5 /* LinkPreview.swift */; };
|
||||
FDF0B740280402C4004C14C5 /* Job.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B73F280402C4004C14C5 /* Job.swift */; };
|
||||
FDF0B7422804EA4F004C14C5 /* _002_SetupStandardJobs.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7412804EA4F004C14C5 /* _002_SetupStandardJobs.swift */; };
|
||||
FDF0B7442804EF1B004C14C5 /* JobRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7432804EF1B004C14C5 /* JobRunner.swift */; };
|
||||
FDF0B7472804F0CE004C14C5 /* DisappearingMessagesJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7462804F0CE004C14C5 /* DisappearingMessagesJob.swift */; };
|
||||
FDF0B74928060D13004C14C5 /* QuotedReplyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B74828060D13004C14C5 /* QuotedReplyModel.swift */; };
|
||||
FDF0B74B28061F7A004C14C5 /* InteractionAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B74A28061F7A004C14C5 /* InteractionAttachment.swift */; };
|
||||
|
@ -1815,7 +1820,7 @@
|
|||
FD17D79827F40AB800122BE0 /* _003_YDBToGRDBMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _003_YDBToGRDBMigration.swift; sourceTree = "<group>"; };
|
||||
FD17D79B27F40B2E00122BE0 /* SMKLegacyModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMKLegacyModels.swift; sourceTree = "<group>"; };
|
||||
FD17D79F27F40CC800122BE0 /* _001_InitialSetupMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _001_InitialSetupMigration.swift; sourceTree = "<group>"; };
|
||||
FD17D7A327F40F8100122BE0 /* _002_YDBToGRDBMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _002_YDBToGRDBMigration.swift; sourceTree = "<group>"; };
|
||||
FD17D7A327F40F8100122BE0 /* _003_YDBToGRDBMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _003_YDBToGRDBMigration.swift; sourceTree = "<group>"; };
|
||||
FD17D7A627F41AF000122BE0 /* SSKLegacyModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSKLegacyModels.swift; sourceTree = "<group>"; };
|
||||
FD17D7A927F41BF500122BE0 /* SnodeSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnodeSet.swift; sourceTree = "<group>"; };
|
||||
FD17D7AD27F41C4300122BE0 /* SnodeReceivedMessageInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnodeReceivedMessageInfo.swift; sourceTree = "<group>"; };
|
||||
|
@ -1836,7 +1841,7 @@
|
|||
FD17D7D727F658E200122BE0 /* SSKDestination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSKDestination.swift; sourceTree = "<group>"; };
|
||||
FD17D7E027F67BD400122BE0 /* SnodeReceivedMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnodeReceivedMessage.swift; sourceTree = "<group>"; };
|
||||
FD17D7E427F6A09900122BE0 /* Identity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Identity.swift; sourceTree = "<group>"; };
|
||||
FD17D7E627F6A16700122BE0 /* _002_YDBToGRDBMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _002_YDBToGRDBMigration.swift; sourceTree = "<group>"; };
|
||||
FD17D7E627F6A16700122BE0 /* _003_YDBToGRDBMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _003_YDBToGRDBMigration.swift; sourceTree = "<group>"; };
|
||||
FD17D7E927F6A1C600122BE0 /* SUKLegacyModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SUKLegacyModels.swift; sourceTree = "<group>"; };
|
||||
FD28A4F127E990E800FF65E7 /* BlockingManagerRemovalMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockingManagerRemovalMigration.swift; sourceTree = "<group>"; };
|
||||
FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockListUIUtils.swift; sourceTree = "<group>"; };
|
||||
|
@ -1846,6 +1851,9 @@
|
|||
FD5D200E27AA2B6000FEA984 /* MessageRequestResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestResponse.swift; sourceTree = "<group>"; };
|
||||
FD5D201027AA331F00FEA984 /* ConfigurationMessage+Convenience.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfigurationMessage+Convenience.swift"; sourceTree = "<group>"; };
|
||||
FD659ABF27A7649600F12C02 /* MessageRequestsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsViewController.swift; sourceTree = "<group>"; };
|
||||
FD6A7A682818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetrieveDefaultOpenGroupRoomsJob.swift; sourceTree = "<group>"; };
|
||||
FD6A7A6A2818C17C00035AC1 /* UpdateProfilePictureJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateProfilePictureJob.swift; sourceTree = "<group>"; };
|
||||
FD6A7A6C2818C61500035AC1 /* _002_SetupStandardJobs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _002_SetupStandardJobs.swift; sourceTree = "<group>"; };
|
||||
FD705A8B278CDB5600F16121 /* SAEScreenLockViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SAEScreenLockViewController.swift; sourceTree = "<group>"; };
|
||||
FD705A8D278CE29800F16121 /* String+Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Localization.swift"; sourceTree = "<group>"; };
|
||||
FD705A8F278CEBBC00F16121 /* ShareAppExtensionContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareAppExtensionContext.swift; sourceTree = "<group>"; };
|
||||
|
@ -1855,6 +1863,8 @@
|
|||
FD859EFF27C4691300510D0C /* MockDataGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDataGenerator.swift; sourceTree = "<group>"; };
|
||||
FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsCell.swift; sourceTree = "<group>"; };
|
||||
FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsMigration.swift; sourceTree = "<group>"; };
|
||||
FD90040E2818AB6D00ABAAF6 /* GetSnodePoolJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetSnodePoolJob.swift; sourceTree = "<group>"; };
|
||||
FD9004132818AD0B00ABAAF6 /* _002_SetupStandardJobs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _002_SetupStandardJobs.swift; sourceTree = "<group>"; };
|
||||
FD9039443F7CB729CF71350E /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
FDA8EAFD280E8B78002B68E5 /* FailedMessagesJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FailedMessagesJob.swift; sourceTree = "<group>"; };
|
||||
FDA8EAFF280E8D58002B68E5 /* FailedAttachmentDownloadsJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FailedAttachmentDownloadsJob.swift; sourceTree = "<group>"; };
|
||||
|
@ -2853,8 +2863,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
FDF0B7452804F0A8004C14C5 /* Types */,
|
||||
FDF0B7432804EF1B004C14C5 /* JobRunner.swift */,
|
||||
FDE77F68280F9EDA002CFC5D /* JobRunnerError.swift */,
|
||||
C352A2F425574B4700338F3E /* LegacyJob.swift */,
|
||||
C352A3922557883D00338F3E /* JobDelegate.swift */,
|
||||
C352A3882557876500338F3E /* JobQueue.swift */,
|
||||
|
@ -3272,6 +3280,7 @@
|
|||
C3C2A5BA255385ED00C340D1 /* OnionRequestAPI.swift */,
|
||||
C3C2A5BB255385ED00C340D1 /* OnionRequestAPI+Encryption.swift */,
|
||||
C3C2A5BE255385EE00C340D1 /* SnodeAPI.swift */,
|
||||
FD90040E2818AB6D00ABAAF6 /* GetSnodePoolJob.swift */,
|
||||
C3C2A5B6255385EC00C340D1 /* SnodeMessage.swift */,
|
||||
C3C2A5CD255385F300C340D1 /* Utilities */,
|
||||
);
|
||||
|
@ -3306,6 +3315,7 @@
|
|||
B8A582AC258C653C00AFD84C /* Crypto */,
|
||||
B8A582AB258C64E800AFD84C /* Database */,
|
||||
B8A582B0258C66C900AFD84C /* General */,
|
||||
FD9004102818ABB000ABAAF6 /* JobRunner */,
|
||||
B8A582AF258C665E00AFD84C /* Media */,
|
||||
B8A582B9258C696200AFD84C /* Messaging */,
|
||||
B8A582AE258C65D000AFD84C /* Networking */,
|
||||
|
@ -3331,7 +3341,6 @@
|
|||
C3C2A7802553AA6300C340D1 /* Protos */,
|
||||
C3C2A70A25539DF900C340D1 /* Meta */,
|
||||
C32C5BB9256DC7C4003C73A2 /* To Do */,
|
||||
C3BBE0752554CDA60050F1E3 /* Configuration.swift */,
|
||||
C3BBE07F2554CDD70050F1E3 /* Storage.swift */,
|
||||
C32C5BCB256DC818003C73A2 /* Database */,
|
||||
C300A5BB2554AFFB00555489 /* Messages */,
|
||||
|
@ -3520,6 +3529,7 @@
|
|||
C33FD9AC255A548A00E217F9 /* SignalUtilitiesKit */,
|
||||
C331FF1C2558F9D300070591 /* SessionUIKit */,
|
||||
C3C2A6F125539DE700C340D1 /* SessionMessagingKit */,
|
||||
C3BBE0752554CDA60050F1E3 /* Configuration.swift */,
|
||||
C3C2A5A0255385C100C340D1 /* SessionSnodeKit */,
|
||||
C3C2A67A255388CC00C340D1 /* SessionUtilitiesKit */,
|
||||
D221A08C169C9E5E00537ABF /* Frameworks */,
|
||||
|
@ -3648,7 +3658,6 @@
|
|||
FD09799A27FFC82D00936362 /* Quote.swift */,
|
||||
FDF0B73B27FFD3D6004C14C5 /* LinkPreview.swift */,
|
||||
FDE77F6A280FEB28002CFC5D /* ControlMessageProcessRecord.swift */,
|
||||
FDF0B73F280402C4004C14C5 /* Job.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3686,7 +3695,8 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
FD17D79F27F40CC800122BE0 /* _001_InitialSetupMigration.swift */,
|
||||
FD17D7A327F40F8100122BE0 /* _002_YDBToGRDBMigration.swift */,
|
||||
FD6A7A6C2818C61500035AC1 /* _002_SetupStandardJobs.swift */,
|
||||
FD17D7A327F40F8100122BE0 /* _003_YDBToGRDBMigration.swift */,
|
||||
);
|
||||
path = Migrations;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3744,7 +3754,8 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
FD17D7C927F546D900122BE0 /* _001_InitialSetupMigration.swift */,
|
||||
FD17D7E627F6A16700122BE0 /* _002_YDBToGRDBMigration.swift */,
|
||||
FD9004132818AD0B00ABAAF6 /* _002_SetupStandardJobs.swift */,
|
||||
FD17D7E627F6A16700122BE0 /* _003_YDBToGRDBMigration.swift */,
|
||||
);
|
||||
path = Migrations;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3753,6 +3764,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
FD17D7E427F6A09900122BE0 /* Identity.swift */,
|
||||
FDF0B73F280402C4004C14C5 /* Job.swift */,
|
||||
FD17D7CC27F546FF00122BE0 /* Setting.swift */,
|
||||
);
|
||||
path = Models;
|
||||
|
@ -3801,12 +3813,23 @@
|
|||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FD9004102818ABB000ABAAF6 /* JobRunner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FDF0B7432804EF1B004C14C5 /* JobRunner.swift */,
|
||||
FDE77F68280F9EDA002CFC5D /* JobRunnerError.swift */,
|
||||
);
|
||||
path = JobRunner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FDF0B7452804F0A8004C14C5 /* Types */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FDF0B7462804F0CE004C14C5 /* DisappearingMessagesJob.swift */,
|
||||
FDA8EAFD280E8B78002B68E5 /* FailedMessagesJob.swift */,
|
||||
FDA8EAFF280E8D58002B68E5 /* FailedAttachmentDownloadsJob.swift */,
|
||||
FD6A7A6A2818C17C00035AC1 /* UpdateProfilePictureJob.swift */,
|
||||
FD6A7A682818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift */,
|
||||
C352A2FE25574B6300338F3E /* MessageSendJob.swift */,
|
||||
C352A31225574F5200338F3E /* MessageReceiveJob.swift */,
|
||||
C352A32E2557549C00338F3E /* NotifyPushServerJob.swift */,
|
||||
|
@ -4792,7 +4815,7 @@
|
|||
C3C2A5C7255385EE00C340D1 /* SnodeAPI.swift in Sources */,
|
||||
C3C2A5C6255385EE00C340D1 /* Notification+OnionRequestAPI.swift in Sources */,
|
||||
FD17D7AA27F41BF500122BE0 /* SnodeSet.swift in Sources */,
|
||||
FD17D7A427F40F8100122BE0 /* _002_YDBToGRDBMigration.swift in Sources */,
|
||||
FD17D7A427F40F8100122BE0 /* _003_YDBToGRDBMigration.swift in Sources */,
|
||||
C3C2A5DC2553860B00C340D1 /* Promise+Threading.swift in Sources */,
|
||||
C3C2A5C4255385EE00C340D1 /* OnionRequestAPI+Encryption.swift in Sources */,
|
||||
FD17D7D227F5797A00122BE0 /* SSKEndpoint.swift in Sources */,
|
||||
|
@ -4802,9 +4825,11 @@
|
|||
FD17D7A727F41AF000122BE0 /* SSKLegacyModels.swift in Sources */,
|
||||
C3C2A5C2255385EE00C340D1 /* Configuration.swift in Sources */,
|
||||
FD17D7D827F658E200122BE0 /* SSKDestination.swift in Sources */,
|
||||
FD6A7A6D2818C61500035AC1 /* _002_SetupStandardJobs.swift in Sources */,
|
||||
FD17D7B327F51E5B00122BE0 /* SSKSetting.swift in Sources */,
|
||||
FD17D7AE27F41C4300122BE0 /* SnodeReceivedMessageInfo.swift in Sources */,
|
||||
C3C2A5C3255385EE00C340D1 /* OnionRequestAPI.swift in Sources */,
|
||||
FD90040F2818AB6D00ABAAF6 /* GetSnodePoolJob.swift in Sources */,
|
||||
FD17D7D427F6584600122BE0 /* SSKError.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -4832,6 +4857,7 @@
|
|||
B8856E09256F1676001CE70E /* UIDevice+featureSupport.swift in Sources */,
|
||||
B8856DEF256F161F001CE70E /* NSString+SSK.m in Sources */,
|
||||
FD09796727F6B0B600936362 /* Sodium+Conversion.swift in Sources */,
|
||||
FD9004122818ABDC00ABAAF6 /* Job.swift in Sources */,
|
||||
FDF0B74D280664E9004C14C5 /* PersistableRecord+Utilities.swift in Sources */,
|
||||
FD09797927FAB7E800936362 /* ImageFormat.swift in Sources */,
|
||||
C32C5DC9256DD935003C73A2 /* ProxiedContentDownloader.swift in Sources */,
|
||||
|
@ -4839,6 +4865,7 @@
|
|||
C3D9E43125676D3D0040E4F3 /* Configuration.swift in Sources */,
|
||||
C32C5DD2256DD9E5003C73A2 /* LRUCache.swift in Sources */,
|
||||
FD705A94278D052B00F16121 /* UITableView+ReusableView.swift in Sources */,
|
||||
FD9004152818B46300ABAAF6 /* JobRunner.swift in Sources */,
|
||||
C3A7211A2558BCA10043A11F /* DiffieHellman.swift in Sources */,
|
||||
C32C5FA1256DFED5003C73A2 /* NSArray+Functional.m in Sources */,
|
||||
C3A7225E2558C38D0043A11F /* Promise+Retaining.swift in Sources */,
|
||||
|
@ -4886,16 +4913,18 @@
|
|||
C32C5A48256DB8F0003C73A2 /* BuildConfiguration.swift in Sources */,
|
||||
FD17D7BF27F51F8200122BE0 /* ColumnExpressible.swift in Sources */,
|
||||
FD17D7E527F6A09900122BE0 /* Identity.swift in Sources */,
|
||||
FD9004142818AD0B00ABAAF6 /* _002_SetupStandardJobs.swift in Sources */,
|
||||
B87EF18126377A1D00124B3C /* Features.swift in Sources */,
|
||||
FD09797727FAB7A600936362 /* Data+Image.swift in Sources */,
|
||||
C300A60D2554B31900555489 /* Logging.swift in Sources */,
|
||||
B8FF8EA625C11FEF004D1F22 /* IPv4.swift in Sources */,
|
||||
C3D9E35525675EE10040E4F3 /* MIMETypeUtil.m in Sources */,
|
||||
FD705A8E278CE29800F16121 /* String+Localization.swift in Sources */,
|
||||
FD9004162818B46700ABAAF6 /* JobRunnerError.swift in Sources */,
|
||||
FD09797227FAA2F500936362 /* Optional+Utilities.swift in Sources */,
|
||||
C3A7219A2558C1660043A11F /* AnyPromise+Conversion.swift in Sources */,
|
||||
C300A6322554B6D100555489 /* NSDate+Timestamp.mm in Sources */,
|
||||
FD17D7E727F6A16700122BE0 /* _002_YDBToGRDBMigration.swift in Sources */,
|
||||
FD17D7E727F6A16700122BE0 /* _003_YDBToGRDBMigration.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -4909,7 +4938,6 @@
|
|||
C3A3A156256E1B91004D228D /* ProtoUtils.m in Sources */,
|
||||
FD09799927FFC1A300936362 /* Attachment.swift in Sources */,
|
||||
C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */,
|
||||
FDE77F69280F9EDA002CFC5D /* JobRunnerError.swift in Sources */,
|
||||
FDF0B74928060D13004C14C5 /* QuotedReplyModel.swift in Sources */,
|
||||
C352A32F2557549C00338F3E /* NotifyPushServerJob.swift in Sources */,
|
||||
7B4C75CB26B37E0F0000AC89 /* UnsendRequest.swift in Sources */,
|
||||
|
@ -4919,6 +4947,7 @@
|
|||
FD5D201127AA331F00FEA984 /* ConfigurationMessage+Convenience.swift in Sources */,
|
||||
C32C5A13256DB7A5003C73A2 /* PushNotificationAPI.swift in Sources */,
|
||||
C32A026325A801AA000ED5D4 /* NSData+messagePadding.m in Sources */,
|
||||
FD6A7A6B2818C17C00035AC1 /* UpdateProfilePictureJob.swift in Sources */,
|
||||
C352A3932557883D00338F3E /* JobDelegate.swift in Sources */,
|
||||
C32C5B84256DC54F003C73A2 /* SSKEnvironment.m in Sources */,
|
||||
C3A3A108256E1A5C004D228D /* OWSIncomingMessageFinder.m in Sources */,
|
||||
|
@ -4937,7 +4966,6 @@
|
|||
C32C5CA4256DD1DC003C73A2 /* TSAccountManager.m in Sources */,
|
||||
C352A3892557876500338F3E /* JobQueue.swift in Sources */,
|
||||
C3BBE0B52554F0E10050F1E3 /* ProofOfWork.swift in Sources */,
|
||||
FDF0B740280402C4004C14C5 /* Job.swift in Sources */,
|
||||
C32C59C1256DB41F003C73A2 /* TSGroupThread.m in Sources */,
|
||||
C3A3A08F256E1728004D228D /* FullTextSearchFinder.swift in Sources */,
|
||||
FDF0B7472804F0CE004C14C5 /* DisappearingMessagesJob.swift in Sources */,
|
||||
|
@ -4990,6 +5018,7 @@
|
|||
C32C5E15256DDC78003C73A2 /* SSKPreferences.swift in Sources */,
|
||||
C32C5D9C256DD6DC003C73A2 /* OWSOutgoingReceiptManager.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 */,
|
||||
|
@ -5018,7 +5047,6 @@
|
|||
C3A3A0EC256E1949004D228D /* OWSRecipientIdentity.m in Sources */,
|
||||
FDF0B74B28061F7A004C14C5 /* InteractionAttachment.swift in Sources */,
|
||||
B8F5F56525EC8453003BF8D4 /* Notification+Contacts.swift in Sources */,
|
||||
FDF0B7442804EF1B004C14C5 /* JobRunner.swift in Sources */,
|
||||
C32C5AB2256DBE8F003C73A2 /* TSMessage.m in Sources */,
|
||||
FD09796E27FA6D0000936362 /* Contact.swift in Sources */,
|
||||
C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */,
|
||||
|
|
|
@ -165,16 +165,10 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
|
|||
}
|
||||
}
|
||||
|
||||
// Re-populate snode pool if needed
|
||||
SnodeAPI.getSnodePool().retainUntilComplete()
|
||||
|
||||
// Onion request path countries cache
|
||||
DispatchQueue.global(qos: .utility).sync {
|
||||
let _ = IP2Country.shared.populateCacheIfNeeded()
|
||||
}
|
||||
|
||||
// Get default open group rooms if needed
|
||||
OpenGroupAPIV2.getDefaultRoomsIfNeeded()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
|
|
|
@ -162,9 +162,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
guard !CurrentAppContext().isRunningTests else { return }
|
||||
|
||||
// FIXME: We should move this somewhere to prevent typos from breaking it
|
||||
let sharedUserDefaults: UserDefaults? = UserDefaults(suiteName: "group.com.loki-project.loki-messenger")
|
||||
sharedUserDefaults?[.isMainAppActive] = true
|
||||
UserDefaults.sharedLokiProject?[.isMainAppActive] = true
|
||||
|
||||
ensureRootViewController()
|
||||
adapt(appMode: AppModeManager.getAppModeOrSystemDefault())
|
||||
|
@ -186,8 +184,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
clearAllNotificationsAndRestoreBadgeCount()
|
||||
|
||||
let sharedUserDefaults: UserDefaults? = UserDefaults(suiteName: "group.com.loki-project.loki-messenger")
|
||||
sharedUserDefaults?[.isMainAppActive] = false
|
||||
UserDefaults.sharedLokiProject?[.isMainAppActive] = false
|
||||
|
||||
DDLog.flushLog()
|
||||
}
|
||||
|
@ -258,7 +255,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
enableBackgroundRefreshIfNecessary()
|
||||
JobRunner.appDidBecomeActive()
|
||||
|
||||
SnodeAPI.getSnodePool().retainUntilComplete()
|
||||
startPollersIfNeeded()
|
||||
|
||||
if CurrentAppContext().isMainApp {
|
||||
|
|
|
@ -226,9 +226,8 @@ NSString *const ReportedApplicationStateDidChangeNotification = @"ReportedApplic
|
|||
- (void)setMainAppBadgeNumber:(NSInteger)value
|
||||
{
|
||||
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:value];
|
||||
NSUserDefaults *sharedUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.loki-project.loki-messenger"];
|
||||
[sharedUserDefaults setInteger:value forKey:@"currentBadgeNumber"];
|
||||
[sharedUserDefaults synchronize];
|
||||
[[NSUserDefaults sharedLokiProject] setInteger:value forKey:@"currentBadgeNumber"];
|
||||
[[NSUserDefaults sharedLokiProject] synchronize];
|
||||
}
|
||||
|
||||
- (nullable UIViewController *)frontmostViewController
|
||||
|
|
|
@ -8,7 +8,7 @@ import SessionMessagingKit
|
|||
import SessionUtilitiesKit
|
||||
|
||||
public enum SyncPushTokensJob: JobExecutor {
|
||||
public static let maxFailureCount: UInt = 0
|
||||
public static let maxFailureCount: Int = -1
|
||||
public static let requiresThreadId: Bool = false
|
||||
public static let requiresInteractionId: Bool = false
|
||||
|
||||
|
@ -18,12 +18,8 @@ public enum SyncPushTokensJob: JobExecutor {
|
|||
failure: @escaping (Job, Error?, Bool) -> (),
|
||||
deferred: @escaping (Job) -> ()
|
||||
) {
|
||||
// Don't schedule run when inactive or not in main app
|
||||
var isMainAppActive = false
|
||||
if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") {
|
||||
isMainAppActive = sharedUserDefaults[.isMainAppActive]
|
||||
}
|
||||
guard isMainAppActive else {
|
||||
// Don't run when inactive or not in main app
|
||||
guard (UserDefaults.sharedLokiProject?[.isMainAppActive]).defaulting(to: false) else {
|
||||
deferred(job) // Don't need to do anything if it's not the main app
|
||||
return
|
||||
}
|
||||
|
|
|
@ -278,29 +278,5 @@ enum _001_InitialSetupMigration: Migration {
|
|||
|
||||
t.uniqueKey([.threadId, .sentTimestampMs, .serverHash, .openGroupMessageServerId])
|
||||
}
|
||||
|
||||
try db.create(table: Job.self) { t in
|
||||
t.column(.id, .integer)
|
||||
.notNull()
|
||||
.primaryKey(autoincrement: true)
|
||||
t.column(.failureCount, .integer)
|
||||
.notNull()
|
||||
.defaults(to: 0)
|
||||
t.column(.variant, .integer)
|
||||
.notNull()
|
||||
.indexed() // Quicker querying
|
||||
t.column(.behaviour, .integer).notNull() // TODO: Indexed???
|
||||
t.column(.nextRunTimestamp, .double)
|
||||
.notNull() // TODO: Should this just be nullable??? (or do we want to fetch by this?)
|
||||
.indexed() // Quicker querying
|
||||
.defaults(to: 0)
|
||||
t.column(.threadId, .text)
|
||||
.indexed() // Quicker querying
|
||||
.references(SessionThread.self, onDelete: .cascade) // Delete if thread deleted
|
||||
t.column(.interactionId, .text)
|
||||
.indexed() // Quicker querying
|
||||
.references(Interaction.self, onDelete: .cascade) // Delete if interaction deleted
|
||||
t.column(.details, .blob)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,32 +17,28 @@ enum _002_SetupStandardJobs: Migration {
|
|||
try autoreleasepool {
|
||||
// TODO: Add additional jobs from the AppDelegate
|
||||
_ = try Job(
|
||||
failureCount: 0,
|
||||
variant: .disappearingMessages,
|
||||
behaviour: .recurringOnLaunch,
|
||||
nextRunTimestamp: 0
|
||||
behaviour: .recurringOnLaunchBlockingOncePerSession
|
||||
).inserted(db)
|
||||
|
||||
_ = try Job(
|
||||
failureCount: 0,
|
||||
variant: .failedMessages,
|
||||
behaviour: .recurringOnLaunch,
|
||||
nextRunTimestamp: 0
|
||||
behaviour: .recurringOnLaunchBlocking
|
||||
).inserted(db)
|
||||
|
||||
_ = try Job(
|
||||
failureCount: 0,
|
||||
variant: .failedAttachmentDownloads,
|
||||
behaviour: .recurringOnLaunch,
|
||||
nextRunTimestamp: 0
|
||||
behaviour: .recurringOnLaunchBlocking
|
||||
).inserted(db)
|
||||
|
||||
// Note: This job exists in the 'Session' target but that doesn't have it's own migrations
|
||||
_ = try Job(
|
||||
failureCount: 0,
|
||||
variant: .syncPushTokens,
|
||||
behaviour: .recurringOnLaunch,
|
||||
nextRunTimestamp: 0
|
||||
variant: .updateProfilePicture,
|
||||
behaviour: .recurringOnActive
|
||||
).inserted(db)
|
||||
|
||||
_ = try Job(
|
||||
variant: .retrieveDefaultOpenGroupRooms,
|
||||
behaviour: .recurringOnActive
|
||||
).inserted(db)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -334,6 +334,11 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu
|
|||
}
|
||||
}
|
||||
|
||||
// Delete any jobs associated to this interaction
|
||||
try Job
|
||||
.filter(Job.Columns.interactionId == id)
|
||||
.deleteAll(db)
|
||||
|
||||
return try performDelete(db)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,6 +120,17 @@ public struct SessionThread: Codable, Identifiable, Equatable, FetchableRecord,
|
|||
self.notificationSound = notificationSound
|
||||
self.mutedUntilTimestamp = mutedUntilTimestamp
|
||||
}
|
||||
|
||||
// MARK: - Custom Database Interaction
|
||||
|
||||
public func delete(_ db: Database) throws -> Bool {
|
||||
// Delete any jobs associated to this thread
|
||||
try Job
|
||||
.filter(Job.Columns.threadId == id)
|
||||
.deleteAll(db)
|
||||
|
||||
return try performDelete(db)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - GRDB Interactions
|
||||
|
|
|
@ -7,7 +7,7 @@ import SessionSnodeKit
|
|||
import SignalCoreKit
|
||||
|
||||
public enum AttachmentDownloadJob: JobExecutor {
|
||||
public static var maxFailureCount: UInt = 10
|
||||
public static var maxFailureCount: Int = 10
|
||||
public static var requiresThreadId: Bool = true
|
||||
public static let requiresInteractionId: Bool = true
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import GRDB
|
|||
import SessionUtilitiesKit
|
||||
|
||||
public enum DisappearingMessagesJob: JobExecutor {
|
||||
public static let maxFailureCount: UInt = 0
|
||||
public static let maxFailureCount: Int = -1
|
||||
public static let requiresThreadId: Bool = false
|
||||
public static let requiresInteractionId: Bool = false
|
||||
|
||||
|
@ -25,8 +25,15 @@ public enum DisappearingMessagesJob: JobExecutor {
|
|||
.filter(sql: "(\(Interaction.Columns.expiresStartedAtMs) + (\(Interaction.Columns.expiresInSeconds) * 1000) <= \(timestampNowMs)")
|
||||
.deleteAll(db)
|
||||
|
||||
// Update the next run timestamp for the DisappearingMessagesJob
|
||||
// Update the next run timestamp for the DisappearingMessagesJob (if the call
|
||||
// to 'updateNextRunIfNeeded' returns 'nil' then it doesn't need to re-run so
|
||||
// should have it's 'nextRunTimestamp' cleared)
|
||||
return updateNextRunIfNeeded(db)
|
||||
.defaulting(
|
||||
to: try job
|
||||
.with(nextRunTimestamp: 0)
|
||||
.saved(db)
|
||||
)
|
||||
}
|
||||
|
||||
success(updatedJob ?? job, false)
|
||||
|
@ -40,12 +47,8 @@ public enum DisappearingMessagesJob: JobExecutor {
|
|||
|
||||
public extension DisappearingMessagesJob {
|
||||
@discardableResult static func updateNextRunIfNeeded(_ db: Database) -> Job? {
|
||||
// Don't schedule run when inactive or not in main app
|
||||
var isMainAppActive = false
|
||||
if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") {
|
||||
isMainAppActive = sharedUserDefaults[.isMainAppActive]
|
||||
}
|
||||
guard isMainAppActive else { return nil }
|
||||
// Don't run when inactive or not in main app
|
||||
guard (UserDefaults.sharedLokiProject?[.isMainAppActive]).defaulting(to: false) else { return nil }
|
||||
|
||||
// If there is another expiring message then update the job to run 1 second after it's meant to expire
|
||||
let nextExpirationTimestampMs: Double? = try? Double
|
||||
|
|
|
@ -6,7 +6,7 @@ import SignalCoreKit
|
|||
import SessionUtilitiesKit
|
||||
|
||||
public enum FailedAttachmentDownloadsJob: JobExecutor {
|
||||
public static let maxFailureCount: UInt = 0
|
||||
public static let maxFailureCount: Int = -1
|
||||
public static let requiresThreadId: Bool = false
|
||||
public static let requiresInteractionId: Bool = false
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import SignalCoreKit
|
|||
import SessionUtilitiesKit
|
||||
|
||||
public enum FailedMessagesJob: JobExecutor {
|
||||
public static let maxFailureCount: UInt = 0
|
||||
public static let maxFailureCount: Int = -1
|
||||
public static let requiresThreadId: Bool = false
|
||||
public static let requiresInteractionId: Bool = false
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import PromiseKit
|
|||
import SessionUtilitiesKit
|
||||
|
||||
public enum MessageReceiveJob: JobExecutor {
|
||||
public static var maxFailureCount: UInt = 10
|
||||
public static var maxFailureCount: Int = 10
|
||||
public static var requiresThreadId: Bool = true
|
||||
public static let requiresInteractionId: Bool = false
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import SessionUtilitiesKit
|
|||
import SessionSnodeKit
|
||||
|
||||
public enum MessageSendJob: JobExecutor {
|
||||
public static var maxFailureCount: UInt = 10
|
||||
public static var maxFailureCount: Int = 10
|
||||
public static var requiresThreadId: Bool = true
|
||||
public static let requiresInteractionId: Bool = false // Some messages don't have interactions
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import SessionSnodeKit
|
|||
import SessionUtilitiesKit
|
||||
|
||||
public enum NotifyPushServerJob: JobExecutor {
|
||||
public static var maxFailureCount: UInt = 20
|
||||
public static var maxFailureCount: Int = 20
|
||||
public static var requiresThreadId: Bool = false
|
||||
public static let requiresInteractionId: Bool = false
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public enum RetrieveDefaultOpenGroupRoomsJob: JobExecutor {
|
||||
public static let maxFailureCount: Int = -1
|
||||
public static let requiresThreadId: Bool = false
|
||||
public static let requiresInteractionId: Bool = false
|
||||
|
||||
public static func run(
|
||||
_ job: Job,
|
||||
success: @escaping (Job, Bool) -> (),
|
||||
failure: @escaping (Job, Error?, Bool) -> (),
|
||||
deferred: @escaping (Job) -> ()
|
||||
) {
|
||||
// Don't run when inactive or not in main app
|
||||
guard (UserDefaults.sharedLokiProject?[.isMainAppActive]).defaulting(to: false) else {
|
||||
deferred(job) // Don't need to do anything if it's not the main app
|
||||
return
|
||||
}
|
||||
|
||||
OpenGroupAPIV2.getDefaultRoomsIfNeeded()
|
||||
.done { _ in success(job, false) }
|
||||
.catch { error in failure(job, error, false) }
|
||||
.retainUntilComplete()
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import PromiseKit
|
|||
import SessionUtilitiesKit
|
||||
|
||||
public enum SendReadReceiptsJob: JobExecutor {
|
||||
public static let maxFailureCount: UInt = 0
|
||||
public static let maxFailureCount: Int = -1
|
||||
public static let requiresThreadId: Bool = false
|
||||
public static let requiresInteractionId: Bool = false
|
||||
private static let minRunFrequency: TimeInterval = 3
|
||||
|
|
46
SessionMessagingKit/Jobs/Types/UpdateProfilePictureJob.swift
Normal file
46
SessionMessagingKit/Jobs/Types/UpdateProfilePictureJob.swift
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public enum UpdateProfilePictureJob: JobExecutor {
|
||||
public static let maxFailureCount: Int = -1
|
||||
public static let requiresThreadId: Bool = false
|
||||
public static let requiresInteractionId: Bool = false
|
||||
|
||||
public static func run(
|
||||
_ job: Job,
|
||||
success: @escaping (Job, Bool) -> (),
|
||||
failure: @escaping (Job, Error?, Bool) -> (),
|
||||
deferred: @escaping (Job) -> ()
|
||||
) {
|
||||
// Don't run when inactive or not in main app
|
||||
guard (UserDefaults.sharedLokiProject?[.isMainAppActive]).defaulting(to: false) else {
|
||||
deferred(job) // Don't need to do anything if it's not the main app
|
||||
return
|
||||
}
|
||||
|
||||
// Only re-upload the profile picture if enough time has passed since the last upload
|
||||
guard
|
||||
let lastProfilePictureUpload: Date = UserDefaults.standard[.lastProfilePictureUpload],
|
||||
Date().timeIntervalSince(lastProfilePictureUpload) > (14 * 24 * 60 * 60)
|
||||
else {
|
||||
deferred(job)
|
||||
return
|
||||
}
|
||||
|
||||
// Note: The user defaults flag is updated in ProfileManager
|
||||
let profile: Profile = Profile.fetchOrCreateCurrentUser()
|
||||
let profilePicture: UIImage? = ProfileManager.profileAvatar(id: profile.id)
|
||||
|
||||
ProfileManager.updateLocal(
|
||||
profileName: profile.name,
|
||||
avatarImage: profilePicture,
|
||||
requiredSync: true,
|
||||
success: { success(job, false) },
|
||||
failure: { error in failure(job, error, false) }
|
||||
)
|
||||
}
|
||||
}
|
|
@ -11,9 +11,4 @@ extension OpenGroupAPIV2 {
|
|||
public static func objc_isUserModerator(_ publicKey: String, for room: String, on server: String) -> Bool {
|
||||
return isUserModerator(publicKey, for: room, on: server)
|
||||
}
|
||||
|
||||
@objc(getDefaultRoomsIfNeeded)
|
||||
public static func objc_getDefaultRoomsIfNeeded() {
|
||||
getDefaultRoomsIfNeeded()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ extension MessageReceiver {
|
|||
///
|
||||
/// **Note:** This is a slightly optimised version of the `decryptWithSessionProtocol` function which just skips
|
||||
/// the validation (handled when the job actually runs) and doesn't throw
|
||||
internal static func extractSenderPublicKey(_ db: Database, from envelope: SNProtoEnvelope) -> String? {
|
||||
public static func extractSenderPublicKey(_ db: Database, from envelope: SNProtoEnvelope) -> String? {
|
||||
guard
|
||||
let ciphertext: Data = envelope.content,
|
||||
let userX25519KeyPair: Box.KeyPair = Identity.fetchUserKeyPair(db)
|
||||
|
|
|
@ -29,11 +29,7 @@ extension MessageReceiver {
|
|||
default: fatalError()
|
||||
}
|
||||
|
||||
var isMainAppActive = false
|
||||
if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") {
|
||||
isMainAppActive = sharedUserDefaults[.isMainAppActive]
|
||||
}
|
||||
guard isMainAppActive else { return }
|
||||
guard (UserDefaults.sharedLokiProject?[.isMainAppActive]).defaulting(to: false) else { return }
|
||||
|
||||
// Touch the thread to update the home screen preview
|
||||
let storage = SNMessagingKitConfiguration.shared.storage
|
||||
|
@ -399,11 +395,7 @@ extension MessageReceiver {
|
|||
|
||||
// Note: `message.sentTimestamp` is in ms
|
||||
let messageSentTimestamp: TimeInterval = TimeInterval((message.sentTimestamp ?? 0) / 1000)
|
||||
|
||||
var isMainAppActive = false
|
||||
if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") {
|
||||
isMainAppActive = sharedUserDefaults[.isMainAppActive]
|
||||
}
|
||||
let isMainAppActive: Bool = (UserDefaults.sharedLokiProject?[.isMainAppActive]).defaulting(to: false)
|
||||
|
||||
// Parse & persist attachments
|
||||
|
||||
|
|
|
@ -89,10 +89,7 @@ public final class MessageSender : NSObject {
|
|||
let (promise, seal) = Promise<Void>.pending()
|
||||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||
|
||||
var isMainAppActive = false
|
||||
if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") {
|
||||
isMainAppActive = sharedUserDefaults[.isMainAppActive]
|
||||
}
|
||||
let isMainAppActive: Bool = (UserDefaults.sharedLokiProject?[.isMainAppActive]).defaulting(to: false)
|
||||
|
||||
// Set the timestamp, sender and recipient
|
||||
if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set
|
||||
|
|
|
@ -124,10 +124,27 @@ public final class ClosedGroupPoller : NSObject {
|
|||
SNLog("Received \(messages.count) new message(s) in closed group with public key: \(groupPublicKey).")
|
||||
|
||||
GRDBStorage.shared.write { db in
|
||||
var jobDetailMessages: [MessageReceiveJob.Details.MessageInfo] = []
|
||||
|
||||
messages.forEach { message in
|
||||
guard let envelope = SNProtoEnvelope.from(message) else { return }
|
||||
|
||||
do {
|
||||
jobDetailMessages.append(
|
||||
MessageReceiveJob.Details.MessageInfo(
|
||||
data: try envelope.serializedData(),
|
||||
serverHash: message.info.hash
|
||||
)
|
||||
)
|
||||
|
||||
// Persist the received message after the MessageReceiveJob is created
|
||||
_ = try message.info.saved(db)
|
||||
}
|
||||
catch {
|
||||
SNLog("Failed to deserialize envelope due to error: \(error).")
|
||||
}
|
||||
}
|
||||
|
||||
JobRunner.add(
|
||||
db,
|
||||
job: Job(
|
||||
|
@ -135,20 +152,11 @@ public final class ClosedGroupPoller : NSObject {
|
|||
behaviour: .runOnce,
|
||||
threadId: groupPublicKey,
|
||||
details: MessageReceiveJob.Details(
|
||||
data: try envelope.serializedData(),
|
||||
serverHash: message.info.hash,
|
||||
messages: jobDetailMessages,
|
||||
isBackgroundPoll: false
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Persist the received message after the MessageReceiveJob is created
|
||||
try message.info.save(db)
|
||||
}
|
||||
catch {
|
||||
SNLog("Failed to deserialize envelope due to error: \(error).")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,9 @@ public final class Poller : NSObject {
|
|||
|
||||
private func poll(_ snode: Snode, seal longTermSeal: Resolver<Void>) -> Promise<Void> {
|
||||
guard isPolling else { return Promise { $0.fulfill(()) } }
|
||||
|
||||
let userPublicKey = getUserHexEncodedPublicKey()
|
||||
|
||||
return SnodeAPI.getRawMessages(from: snode, associatedWith: userPublicKey)
|
||||
.then(on: Threading.pollerQueue) { [weak self] rawResponse -> Promise<Void> in
|
||||
guard let strongSelf = self, strongSelf.isPolling else { return Promise { $0.fulfill(()) } }
|
||||
|
@ -106,6 +108,8 @@ public final class Poller : NSObject {
|
|||
SNLog("Received \(messages.count) new message(s).")
|
||||
|
||||
GRDBStorage.shared.write { db in
|
||||
var threadMessages: [String: [MessageReceiveJob.Details.MessageInfo]] = [:]
|
||||
|
||||
messages.forEach { message in
|
||||
guard let envelope = SNProtoEnvelope.from(message) else { return }
|
||||
|
||||
|
@ -117,6 +121,23 @@ public final class Poller : NSObject {
|
|||
}
|
||||
|
||||
do {
|
||||
threadMessages[threadId ?? ""] = (threadMessages[threadId ?? ""] ?? [])
|
||||
.appending(
|
||||
MessageReceiveJob.Details.MessageInfo(
|
||||
data: try envelope.serializedData(),
|
||||
serverHash: message.info.hash
|
||||
)
|
||||
)
|
||||
|
||||
// Persist the received message after the MessageReceiveJob is created
|
||||
_ = try message.info.saved(db)
|
||||
}
|
||||
catch {
|
||||
SNLog("Failed to deserialize envelope due to error: \(error).")
|
||||
}
|
||||
}
|
||||
|
||||
threadMessages.forEach { threadId, threadMessages in
|
||||
JobRunner.add(
|
||||
db,
|
||||
job: Job(
|
||||
|
@ -124,19 +145,11 @@ public final class Poller : NSObject {
|
|||
behaviour: .runOnce,
|
||||
threadId: threadId,
|
||||
details: MessageReceiveJob.Details(
|
||||
data: try envelope.serializedData(),
|
||||
serverHash: message.info.hash,
|
||||
messages: threadMessages,
|
||||
isBackgroundPoll: false
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Persist the received message after the MessageReceiveJob is created
|
||||
try message.info.save(db)
|
||||
}
|
||||
catch {
|
||||
SNLog("Failed to deserialize envelope due to error: \(error).")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,11 +19,9 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
|
|||
self.notificationContent = request.content.mutableCopy() as? UNMutableNotificationContent
|
||||
|
||||
// Abort if the main app is running
|
||||
var isMainAppActive = false
|
||||
if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") {
|
||||
isMainAppActive = sharedUserDefaults.bool(forKey: "isMainAppActive")
|
||||
guard !(UserDefaults.sharedLokiProject?[.isMainAppActive]).defaulting(to: false) else {
|
||||
return self.completeSilenty()
|
||||
}
|
||||
guard !isMainAppActive else { return self.completeSilenty() }
|
||||
|
||||
// Perform main setup
|
||||
DispatchQueue.main.sync { self.setUpIfNecessary() { } }
|
||||
|
|
|
@ -13,15 +13,18 @@ public enum SNSnodeKit { // Just to make the external API nice
|
|||
identifier: .snodeKit,
|
||||
migrations: [
|
||||
[
|
||||
_001_InitialSetupMigration.self
|
||||
_001_InitialSetupMigration.self,
|
||||
_002_SetupStandardJobs.self
|
||||
],
|
||||
[
|
||||
_002_YDBToGRDBMigration.self
|
||||
_003_YDBToGRDBMigration.self
|
||||
]
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
public static func configure() {
|
||||
// Configure the job executors
|
||||
JobRunner.add(executor: GetSnodePoolJob.self, for: .getSnodePool)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SessionUtilitiesKit
|
||||
|
||||
/// This migration sets up the standard jobs, since we want these jobs to run before any "once-off" jobs we do this migration
|
||||
/// before running the `YDBToGRDBMigration`
|
||||
enum _002_SetupStandardJobs: Migration {
|
||||
static let identifier: String = "SetupStandardJobs"
|
||||
|
||||
static func migrate(_ db: Database) throws {
|
||||
try autoreleasepool {
|
||||
_ = try Job(
|
||||
variant: .getSnodePool,
|
||||
behaviour: .recurringOnActiveBlocking
|
||||
).inserted(db)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import Foundation
|
|||
import GRDB
|
||||
import SessionUtilitiesKit
|
||||
|
||||
enum _002_YDBToGRDBMigration: Migration {
|
||||
enum _003_YDBToGRDBMigration: Migration {
|
||||
static let identifier: String = "YDBToGRDBMigration"
|
||||
|
||||
static func migrate(_ db: Database) throws {
|
||||
|
@ -103,6 +103,7 @@ enum _002_YDBToGRDBMigration: Migration {
|
|||
var lastMessageResults: [String: (hash: String, json: JSON)] = [:]
|
||||
var receivedMessageResults: [String: Set<String>] = [:]
|
||||
|
||||
// TODO: Move into the top read block???
|
||||
Storage.read { transaction in
|
||||
// Extract the received message hashes
|
||||
transaction.enumerateKeysAndObjects(inCollection: Legacy.receivedMessagesCollection) { key, object, _ in
|
24
SessionSnodeKit/GetSnodePoolJob.swift
Normal file
24
SessionSnodeKit/GetSnodePoolJob.swift
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public enum GetSnodePoolJob: JobExecutor {
|
||||
public static let maxFailureCount: Int = -1
|
||||
public static let requiresThreadId: Bool = false
|
||||
public static let requiresInteractionId: Bool = false
|
||||
|
||||
public static func run(
|
||||
_ job: Job,
|
||||
success: @escaping (Job, Bool) -> (),
|
||||
failure: @escaping (Job, Error?, Bool) -> (),
|
||||
deferred: @escaping (Job) -> ()
|
||||
) {
|
||||
SnodeAPI.getSnodePool()
|
||||
.done { _ in success(job, false) }
|
||||
.catch { error in failure(job, error, false) }
|
||||
.retainUntilComplete()
|
||||
}
|
||||
}
|
|
@ -258,7 +258,9 @@ public final class SnodeAPI : NSObject {
|
|||
public static func getSnodePool() -> Promise<Set<Snode>> {
|
||||
loadSnodePoolIfNeeded()
|
||||
let now = Date()
|
||||
let hasSnodePoolExpired = given(GRDBStorage.shared[.lastSnodePoolRefreshDate]) { now.timeIntervalSince($0) > 2 * 60 * 60 } ?? true
|
||||
let hasSnodePoolExpired = given(GRDBStorage.shared[.lastSnodePoolRefreshDate]) {
|
||||
now.timeIntervalSince($0) > 2 * 60 * 60
|
||||
}.defaulting(to: true)
|
||||
let snodePool = SnodeAPI.snodePool
|
||||
let hasInsufficientSnodes = (snodePool.count < minSnodePoolCount)
|
||||
|
||||
|
@ -441,6 +443,7 @@ public final class SnodeAPI : NSObject {
|
|||
// "pubkey_ed25519" : ed25519PublicKey,
|
||||
// "signature" : signature.toBase64()!
|
||||
]
|
||||
|
||||
return invoke(.getMessages, on: snode, associatedWith: publicKey, parameters: parameters)
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,12 @@ public enum SNUtilitiesKit { // Just to make the external API nice
|
|||
identifier: .utilitiesKit,
|
||||
migrations: [
|
||||
[
|
||||
// Intentionally including the '_002_YDBToGRDBMigration' in the first migration
|
||||
// Intentionally including the '_003_YDBToGRDBMigration' in the first migration
|
||||
// set to ensure the 'Identity' data is migrated before any other migrations are
|
||||
// run (some need access to the users publicKey)
|
||||
_001_InitialSetupMigration.self,
|
||||
_002_YDBToGRDBMigration.self
|
||||
_002_SetupStandardJobs.self,
|
||||
_003_YDBToGRDBMigration.self
|
||||
]
|
||||
]
|
||||
)
|
||||
|
|
|
@ -15,6 +15,30 @@ enum _001_InitialSetupMigration: Migration {
|
|||
t.column(.data, .blob).notNull()
|
||||
}
|
||||
|
||||
try db.create(table: Job.self) { t in
|
||||
t.column(.id, .integer)
|
||||
.notNull()
|
||||
.primaryKey(autoincrement: true)
|
||||
t.column(.failureCount, .integer)
|
||||
.notNull()
|
||||
.defaults(to: 0)
|
||||
t.column(.variant, .integer)
|
||||
.notNull()
|
||||
.indexed() // Quicker querying
|
||||
t.column(.behaviour, .integer)
|
||||
.notNull()
|
||||
.indexed() // Quicker querying
|
||||
t.column(.nextRunTimestamp, .double)
|
||||
.notNull()
|
||||
.indexed() // Quicker querying
|
||||
.defaults(to: 0)
|
||||
t.column(.threadId, .text)
|
||||
.indexed() // Quicker querying
|
||||
t.column(.interactionId, .text)
|
||||
.indexed() // Quicker querying
|
||||
t.column(.details, .blob)
|
||||
}
|
||||
|
||||
try db.create(table: Setting.self) { t in
|
||||
t.column(.key, .text)
|
||||
.notNull()
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import Curve25519Kit
|
||||
|
||||
/// This migration sets up the standard jobs, since we want these jobs to run before any "once-off" jobs we do this migration
|
||||
/// before running the `YDBToGRDBMigration`
|
||||
enum _002_SetupStandardJobs: Migration {
|
||||
static let identifier: String = "SetupStandardJobs"
|
||||
|
||||
static func migrate(_ db: Database) throws {
|
||||
try autoreleasepool {
|
||||
// Note: This job exists in the 'Session' target but that doesn't have it's own migrations
|
||||
_ = try Job(
|
||||
variant: .syncPushTokens,
|
||||
behaviour: .recurringOnLaunch
|
||||
).inserted(db)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
|
||||
enum _002_YDBToGRDBMigration: Migration {
|
||||
enum _003_YDBToGRDBMigration: Migration {
|
||||
static let identifier: String = "YDBToGRDBMigration"
|
||||
|
||||
static func migrate(_ db: Database) throws {
|
||||
|
@ -65,6 +65,7 @@ enum _002_YDBToGRDBMigration: Migration {
|
|||
|
||||
throw GRDBStorageError.migrationFailed
|
||||
}
|
||||
print("RAWR publicKey \(userX25519KeyPair.publicKey.toHexString())")
|
||||
try autoreleasepool {
|
||||
// Insert the data into GRDB
|
||||
try Identity(
|
|
@ -2,21 +2,9 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SessionUtilitiesKit
|
||||
import SwiftProtobuf
|
||||
|
||||
public struct Job: Codable, Equatable, Identifiable, FetchableRecord, MutablePersistableRecord, TableRecord, ColumnExpressible {
|
||||
public static var databaseTableName: String { "job" }
|
||||
internal static let threadForeignKey = ForeignKey(
|
||||
[Columns.threadId],
|
||||
to: [SessionThread.Columns.id]
|
||||
)
|
||||
internal static let interactionForeignKey = ForeignKey(
|
||||
[Columns.interactionId],
|
||||
to: [Interaction.Columns.id]
|
||||
)
|
||||
internal static let thread = hasOne(SessionThread.self, using: Job.threadForeignKey)
|
||||
internal static let interaction = hasOne(Interaction.self, using: Job.interactionForeignKey)
|
||||
|
||||
public typealias Columns = CodingKeys
|
||||
public enum CodingKeys: String, CodingKey, ColumnExpression {
|
||||
|
@ -35,13 +23,31 @@ public struct Job: Codable, Equatable, Identifiable, FetchableRecord, MutablePer
|
|||
/// at the timestamp of the next disappearing message
|
||||
case disappearingMessages
|
||||
|
||||
/// This is a recurring job that ensures the app retrieves a service node pool on active
|
||||
///
|
||||
/// **Note:** This is a blocking job so it will run before any other jobs and prevent them from
|
||||
/// running until it's complete
|
||||
case getSnodePool
|
||||
|
||||
/// This is a recurring job that checks if the user needs to update their profile picture on launch, and if so
|
||||
/// attempt to download the latest
|
||||
case updateProfilePicture
|
||||
|
||||
/// This is a recurring job that ensures the app fetches the default open group rooms on launch
|
||||
case retrieveDefaultOpenGroupRooms
|
||||
|
||||
/// This is a recurring job that runs on launch and flags any messages marked as 'sending' to
|
||||
/// be in their 'failed' state
|
||||
///
|
||||
/// **Note:** This is a blocking job so it will run before any other jobs and prevent them from
|
||||
/// running until it's complete
|
||||
case failedMessages = 1000
|
||||
|
||||
/// This is a recurring job that runs on launch and flags any attachments marked as 'uploading' to
|
||||
/// be in their 'failed' state
|
||||
///
|
||||
/// **Note:** This is a blocking job so it will run before any other jobs and prevent them from
|
||||
/// running until it's complete
|
||||
case failedAttachmentDownloads
|
||||
|
||||
/// This is a recurring job that runs on return from background and registeres and uploads the
|
||||
|
@ -84,11 +90,26 @@ public struct Job: Codable, Equatable, Identifiable, FetchableRecord, MutablePer
|
|||
/// the future) in order to be run again
|
||||
case recurring
|
||||
|
||||
/// This job will run once each launch
|
||||
/// This job will run once each launch and may run again during the same session if `nextRunTimestamp`
|
||||
/// gets set
|
||||
case recurringOnLaunch
|
||||
|
||||
/// This job will run once each whenever the app becomes active (launch and return from background)
|
||||
/// This job will run once each launch and may run again during the same session if `nextRunTimestamp`
|
||||
/// gets set, it also must complete before any other jobs can run
|
||||
case recurringOnLaunchBlocking
|
||||
|
||||
/// This job will run once each launch and may run again during the same session if `nextRunTimestamp`
|
||||
/// gets set, it also must complete before any other jobs can run
|
||||
case recurringOnLaunchBlockingOncePerSession
|
||||
|
||||
/// This job will run once each whenever the app becomes active (launch and return from background) and
|
||||
/// may run again during the same session if `nextRunTimestamp` gets set
|
||||
case recurringOnActive
|
||||
|
||||
/// This job will run once each whenever the app becomes active (launch and return from background) and
|
||||
/// may run again during the same session if `nextRunTimestamp` gets set, it also must complete before
|
||||
/// any other jobs can run
|
||||
case recurringOnActiveBlocking
|
||||
}
|
||||
|
||||
/// The `id` value is auto incremented by the database, if the `Job` hasn't been inserted into
|
||||
|
@ -122,16 +143,6 @@ public struct Job: Codable, Equatable, Identifiable, FetchableRecord, MutablePer
|
|||
/// JSON encoded data required for the job
|
||||
public let details: Data?
|
||||
|
||||
// MARK: - Relationships
|
||||
|
||||
public var thread: QueryInterfaceRequest<SessionThread> {
|
||||
request(for: Job.thread)
|
||||
}
|
||||
|
||||
public var interaction: QueryInterfaceRequest<Interaction> {
|
||||
request(for: Job.interaction)
|
||||
}
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
fileprivate init(
|
||||
|
@ -201,26 +212,72 @@ public struct Job: Codable, Equatable, Identifiable, FetchableRecord, MutablePer
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - GRDB Interactions
|
||||
|
||||
extension Job {
|
||||
internal static func filterPendingJobs(excludeFutureJobs: Bool = true) -> QueryInterfaceRequest<Job> {
|
||||
let query: QueryInterfaceRequest<Job> = Job
|
||||
.filter(
|
||||
// TODO: Should this include other behaviours? (what happens if one of the other types fails???? Just leave it until the next launch/active???) Set a 'failureCount' and use that to determine if it should run? (reset on success)
|
||||
// Retrieve all 'runOnce' and 'recurring' jobs
|
||||
[
|
||||
Job.Behaviour.runOnce,
|
||||
Job.Behaviour.recurring
|
||||
].contains(Job.Columns.behaviour) || (
|
||||
// Retrieve any 'recurringOnLaunch' and 'recurringOnActive' jobs that have a
|
||||
// 'nextRunTimestamp'
|
||||
[
|
||||
Job.Behaviour.recurringOnLaunch,
|
||||
Job.Behaviour.recurringOnLaunchBlocking,
|
||||
Job.Behaviour.recurringOnActive,
|
||||
Job.Behaviour.recurringOnActiveBlocking
|
||||
].contains(Job.Columns.behaviour) &&
|
||||
Job.Columns.nextRunTimestamp > 0
|
||||
)
|
||||
)
|
||||
.order(Job.Columns.nextRunTimestamp)
|
||||
.order(Job.Columns.id)
|
||||
|
||||
guard excludeFutureJobs else {
|
||||
return query
|
||||
}
|
||||
|
||||
return query
|
||||
.filter(Job.Columns.nextRunTimestamp <= Date().timeIntervalSince1970)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Convenience
|
||||
|
||||
public extension Job {
|
||||
internal func with(
|
||||
var isBlocking: Bool {
|
||||
switch self.behaviour {
|
||||
case .recurringOnLaunchBlocking,
|
||||
.recurringOnLaunchBlockingOncePerSession,
|
||||
.recurringOnActiveBlocking:
|
||||
return true
|
||||
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
||||
func with(
|
||||
failureCount: UInt = 0,
|
||||
nextRunTimestamp: TimeInterval?
|
||||
nextRunTimestamp: TimeInterval
|
||||
) -> Job {
|
||||
return Job(
|
||||
id: id,
|
||||
failureCount: failureCount,
|
||||
variant: variant,
|
||||
behaviour: behaviour,
|
||||
nextRunTimestamp: (nextRunTimestamp ?? self.nextRunTimestamp),
|
||||
nextRunTimestamp: nextRunTimestamp,
|
||||
threadId: threadId,
|
||||
interactionId: interactionId,
|
||||
details: details
|
||||
)
|
||||
}
|
||||
|
||||
internal func with<T: Encodable>(details: T) -> Job? {
|
||||
func with<T: Encodable>(details: T) -> Job? {
|
||||
guard let detailsData: Data = try? JSONEncoder().encode(details) else { return nil }
|
||||
|
||||
return Job(
|
|
@ -34,6 +34,9 @@ public enum SNUserDefaults {
|
|||
}
|
||||
|
||||
public extension UserDefaults {
|
||||
@objc static var sharedLokiProject: UserDefaults? {
|
||||
UserDefaults(suiteName: "group.com.loki-project.loki-messenger")
|
||||
}
|
||||
|
||||
subscript(bool: SNUserDefaults.Bool) -> Bool {
|
||||
get { return self.bool(forKey: bool.rawValue) }
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public protocol JobExecutor {
|
||||
static var maxFailureCount: UInt { get }
|
||||
/// The maximum number of times the job can fail before it fails permanently
|
||||
///
|
||||
/// **Note:** A value of `-1` means it will retry indefinitely
|
||||
static var maxFailureCount: Int { get }
|
||||
static var requiresThreadId: Bool { get }
|
||||
static var requiresInteractionId: Bool { get }
|
||||
|
||||
|
@ -57,8 +59,8 @@ public final class JobRunner {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Could this be a bottleneck? (single serial queue to process all these jobs? Group by thread?)
|
||||
// TODO: Multi-thread support
|
||||
// TODO: Could this be a bottleneck? (single serial queue to process all these jobs? Group by thread?).
|
||||
// TODO: Multi-thread support.
|
||||
private static let queueKey: DispatchSpecificKey = DispatchSpecificKey<String>()
|
||||
private static let queueContext: String = "JobRunner"
|
||||
private static let internalQueue: DispatchQueue = {
|
||||
|
@ -74,6 +76,7 @@ public final class JobRunner {
|
|||
private static var jobQueue: Atomic<[Job]> = Atomic([])
|
||||
|
||||
private static var jobsCurrentlyRunning: Atomic<Set<Int64>> = Atomic([])
|
||||
private static var perSessionJobsCompleted: Atomic<Set<Int64>> = Atomic([])
|
||||
|
||||
// MARK: - Configuration
|
||||
|
||||
|
@ -182,27 +185,64 @@ public final class JobRunner {
|
|||
.filter(
|
||||
[
|
||||
Job.Behaviour.recurringOnLaunch,
|
||||
Job.Behaviour.recurringOnLaunchBlocking,
|
||||
Job.Behaviour.recurringOnLaunchBlockingOncePerSession,
|
||||
Job.Behaviour.runOnceNextLaunch
|
||||
].contains(Job.Columns.behaviour)
|
||||
)
|
||||
.order(Job.Columns.id)
|
||||
.fetchAll(db)
|
||||
}
|
||||
|
||||
guard let jobsToRun: [Job] = maybeJobsToRun else { return }
|
||||
|
||||
jobQueue.mutate { $0.append(contentsOf: jobsToRun) }
|
||||
jobQueue.mutate {
|
||||
// Insert any blocking jobs after any existing blocking jobs then add
|
||||
// the remaining jobs to the end of the queue
|
||||
let lastBlockingIndex = $0.lastIndex(where: { $0.isBlocking })
|
||||
.defaulting(to: $0.startIndex.advanced(by: -1))
|
||||
.advanced(by: 1)
|
||||
|
||||
$0.insert(
|
||||
contentsOf: jobsToRun.filter { $0.isBlocking },
|
||||
at: lastBlockingIndex
|
||||
)
|
||||
$0.append(
|
||||
contentsOf: jobsToRun.filter { !$0.isBlocking }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public static func appDidBecomeActive() {
|
||||
let maybeJobsToRun: [Job]? = GRDBStorage.shared.read { db in
|
||||
try Job
|
||||
.filter(Job.Columns.behaviour == Job.Behaviour.recurringOnActive)
|
||||
.filter(
|
||||
[
|
||||
Job.Behaviour.recurringOnActive,
|
||||
Job.Behaviour.recurringOnActiveBlocking
|
||||
].contains(Job.Columns.behaviour)
|
||||
)
|
||||
.order(Job.Columns.id)
|
||||
.fetchAll(db)
|
||||
}
|
||||
|
||||
guard let jobsToRun: [Job] = maybeJobsToRun else { return }
|
||||
|
||||
jobQueue.mutate { $0.append(contentsOf: jobsToRun) }
|
||||
jobQueue.mutate {
|
||||
// Insert any blocking jobs after any existing blocking jobs then add
|
||||
// the remaining jobs to the end of the queue
|
||||
let lastBlockingIndex = $0.lastIndex(where: { $0.isBlocking })
|
||||
.defaulting(to: $0.startIndex.advanced(by: -1))
|
||||
.advanced(by: 1)
|
||||
|
||||
$0.insert(
|
||||
contentsOf: jobsToRun.filter { $0.isBlocking },
|
||||
at: lastBlockingIndex
|
||||
)
|
||||
$0.append(
|
||||
contentsOf: jobsToRun.filter { !$0.isBlocking }
|
||||
)
|
||||
}
|
||||
|
||||
// Start the job runner if needed
|
||||
if !isRunning.wrappedValue {
|
||||
|
@ -228,21 +268,14 @@ public final class JobRunner {
|
|||
guard DispatchQueue.getSpecific(key: queueKey) == queueContext else {
|
||||
internalQueue.async {
|
||||
start()
|
||||
}
|
||||
}// TODO: Want to have multiple threads for this (attachment download should be separate - do we even use attachment upload anymore???)
|
||||
return
|
||||
}
|
||||
|
||||
// Get any pending jobs
|
||||
let maybeJobsToRun: [Job]? = GRDBStorage.shared.read { db in
|
||||
try Job
|
||||
.filter(
|
||||
[
|
||||
Job.Behaviour.runOnce,
|
||||
Job.Behaviour.recurring
|
||||
].contains(Job.Columns.behaviour)
|
||||
)
|
||||
.filter(Job.Columns.nextRunTimestamp <= Date().timeIntervalSince1970)
|
||||
.order(Job.Columns.nextRunTimestamp)
|
||||
try Job// TODO: Test this
|
||||
.filterPendingJobs()
|
||||
.fetchAll(db)
|
||||
}
|
||||
|
||||
|
@ -300,6 +333,12 @@ public final class JobRunner {
|
|||
return
|
||||
}
|
||||
|
||||
// If the 'nextRunTimestamp' for the job is in the future then don't run it yet
|
||||
guard nextJob.nextRunTimestamp <= Date().timeIntervalSince1970 else {
|
||||
handleJobDeferred(nextJob)
|
||||
return
|
||||
}
|
||||
|
||||
// Update the state to indicate it's running
|
||||
//
|
||||
// Note: We need to store 'numJobsRemaining' in it's own variable because
|
||||
|
@ -324,21 +363,17 @@ public final class JobRunner {
|
|||
try TimeInterval
|
||||
.fetchOne(
|
||||
db,
|
||||
Job
|
||||
Job// TODO: Test this works as expected
|
||||
.filterPendingJobs(excludeFutureJobs: false)
|
||||
.select(Job.Columns.nextRunTimestamp)
|
||||
.filter(
|
||||
[
|
||||
Job.Behaviour.runOnce,
|
||||
Job.Behaviour.recurring
|
||||
].contains(Job.Columns.behaviour)
|
||||
)
|
||||
.order(Job.Columns.nextRunTimestamp)
|
||||
)
|
||||
}
|
||||
|
||||
guard let nextJobTimestamp: TimeInterval = nextJobTimestamp else { return }
|
||||
|
||||
// If the next job isn't scheduled in the future then just restart the JobRunner immediately
|
||||
let secondsUntilNextJob: TimeInterval = (nextJobTimestamp - Date().timeIntervalSince1970)
|
||||
|
||||
guard secondsUntilNextJob > 0 else {
|
||||
SNLog("[JobRunner] Restarting immediately for job scheduled \(Int(ceil(abs(secondsUntilNextJob)))) second\(Int(ceil(abs(secondsUntilNextJob))) == 1 ? "" : "s")) ago")
|
||||
|
||||
|
@ -378,6 +413,9 @@ public final class JobRunner {
|
|||
.saved(db)
|
||||
}
|
||||
|
||||
case .recurringOnLaunchBlockingOncePerSession:
|
||||
perSessionJobsCompleted.mutate { $0 = $0.inserting(job.id) }
|
||||
|
||||
default: break
|
||||
}
|
||||
|
||||
|
@ -393,17 +431,48 @@ public final class JobRunner {
|
|||
guard GRDBStorage.shared.read({ db in try Job.exists(db, id: job.id ?? -1) }) == true else {
|
||||
SNLog("[JobRunner] \(job.variant) job canceled")
|
||||
jobsCurrentlyRunning.mutate { $0 = $0.removing(job.id) }
|
||||
|
||||
internalQueue.async {
|
||||
runNextJob()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch job.behaviour {
|
||||
// If a "blocking" job failed then rerun it immediately
|
||||
case .recurringOnLaunchBlocking, .recurringOnActiveBlocking:
|
||||
SNLog("[JobRunner] blocking \(job.variant) job failed; retrying immediately")
|
||||
jobQueue.mutate({ $0.insert(job, at: 0) })
|
||||
|
||||
internalQueue.async {
|
||||
runNextJob()
|
||||
}
|
||||
return
|
||||
|
||||
// For "blocking once per session" jobs only rerun it immediately if it hasn't already
|
||||
// run this session
|
||||
case .recurringOnLaunchBlockingOncePerSession:
|
||||
guard !perSessionJobsCompleted.wrappedValue.contains(job.id ?? -1) else { break }
|
||||
|
||||
SNLog("[JobRunner] blocking \(job.variant) job failed; retrying immediately")
|
||||
perSessionJobsCompleted.mutate { $0 = $0.inserting(job.id) }
|
||||
jobQueue.mutate({ $0.insert(job, at: 0) })
|
||||
|
||||
internalQueue.async {
|
||||
runNextJob()
|
||||
}
|
||||
return
|
||||
|
||||
default: break
|
||||
}
|
||||
|
||||
GRDBStorage.shared.write { db in
|
||||
// Check if the job has a 'maxFailureCount' (a value of '0' means it will always retry)
|
||||
let maxFailureCount: UInt = (executorMap.wrappedValue[job.variant]?.maxFailureCount ?? 0)
|
||||
// Get the max failure count for the job (a value of '-1' means it will retry indefinitely)
|
||||
let maxFailureCount: Int = (executorMap.wrappedValue[job.variant]?.maxFailureCount ?? 0)
|
||||
|
||||
guard
|
||||
!permanentFailure &&
|
||||
maxFailureCount > 0 &&
|
||||
maxFailureCount >= 0 &&
|
||||
job.failureCount + 1 < maxFailureCount
|
||||
else {
|
||||
// If the job permanently failed or we have performed all of our retry attempts
|
||||
|
@ -422,8 +491,10 @@ public final class JobRunner {
|
|||
}
|
||||
|
||||
jobsCurrentlyRunning.mutate { $0 = $0.removing(job.id) }
|
||||
internalQueue.async {
|
||||
runNextJob()
|
||||
}
|
||||
}
|
||||
|
||||
/// This function is called when a job neither succeeds or fails (this should only occur if the job has specific logic that makes it dependant
|
||||
/// on other jobs, and it should automatically manage those dependencies)
|
Loading…
Reference in a new issue