From 1bf81a9c5eeb85dddfdde9c58e0f1f1596e630be Mon Sep 17 00:00:00 2001 From: Max Radermacher Date: Fri, 21 Nov 2025 14:48:55 -0600 Subject: [PATCH] Use Cron for periodic remote megaphone updates --- Signal/AppLaunch/AppDelegate.swift | 19 +++--- .../Megaphones/RemoteMegaphoneFetcher.swift | 58 ++----------------- SignalServiceKit/Jobs/Cron.swift | 1 + 3 files changed, 16 insertions(+), 62 deletions(-) diff --git a/Signal/AppLaunch/AppDelegate.swift b/Signal/AppLaunch/AppDelegate.swift index a8a8f75ee3..98201f2840 100644 --- a/Signal/AppLaunch/AppDelegate.swift +++ b/Signal/AppLaunch/AppDelegate.swift @@ -697,14 +697,17 @@ final class AppDelegate: UIResponder, UIApplicationDelegate { } } - appReadiness.runNowOrWhenAppDidBecomeReadyAsync { - Task { - try? await RemoteMegaphoneFetcher( - databaseStorage: SSKEnvironment.shared.databaseStorageRef, - signalService: SSKEnvironment.shared.signalServiceRef - ).syncRemoteMegaphonesIfNecessary() - } - } + let remoteMegaphoneFetcher = RemoteMegaphoneFetcher( + databaseStorage: SSKEnvironment.shared.databaseStorageRef, + signalService: SSKEnvironment.shared.signalServiceRef, + ) + cron.schedulePeriodically( + uniqueKey: .fetchMegaphones, + approximateInterval: 3 * .day, + mustBeRegistered: false, + mustBeConnected: true, + operation: { try await remoteMegaphoneFetcher.syncRemoteMegaphones() }, + ) appReadiness.runNowOrWhenAppDidBecomeReadyAsync { DependenciesBridge.shared.orphanedAttachmentCleaner.beginObserving() diff --git a/Signal/Megaphones/RemoteMegaphoneFetcher.swift b/Signal/Megaphones/RemoteMegaphoneFetcher.swift index 68d9df27d8..2a853524ce 100644 --- a/Signal/Megaphones/RemoteMegaphoneFetcher.swift +++ b/Signal/Megaphones/RemoteMegaphoneFetcher.swift @@ -4,14 +4,14 @@ // import Foundation -public import SignalServiceKit +import SignalServiceKit /// Handles fetching and parsing remote megaphones. -public class RemoteMegaphoneFetcher { +class RemoteMegaphoneFetcher { private let databaseStorage: SDSDatabaseStorage private let signalService: any OWSSignalServiceProtocol - public init( + init( databaseStorage: SDSDatabaseStorage, signalService: any OWSSignalServiceProtocol ) { @@ -22,12 +22,7 @@ public class RemoteMegaphoneFetcher { /// Fetch all remote megaphones currently on the service and persist them /// locally. Removes any locally-persisted remote megaphones that are no /// longer available remotely. - public func syncRemoteMegaphonesIfNecessary() async throws { - let shouldSync = databaseStorage.read { self.shouldSync(transaction: $0) } - guard shouldSync else { - return - } - + func syncRemoteMegaphones() async throws { Logger.info("Beginning remote megaphone fetch.") let megaphones: [RemoteMegaphoneModel] @@ -45,55 +40,10 @@ public class RemoteMegaphoneFetcher { withFetchedMegaphones: megaphones, transaction: transaction ) - - self.recordCompletedSync(transaction: transaction) } } } -// MARK: - Sync conditions - -private extension String { - static let fetcherStoreCollection = "RemoteMegaphoneFetcher" - static let appVersionAtLastFetchKey = "appVersionAtLastFetch" - static let lastFetchDateKey = "lastFetchDate" -} - -private extension RemoteMegaphoneFetcher { - private static let fetcherStore = KeyValueStore(collection: .fetcherStoreCollection) - - private static let delayBetweenSyncs: TimeInterval = 3 * .day - - func shouldSync(transaction: DBReadTransaction) -> Bool { - guard - let appVersionAtLastFetch = Self.fetcherStore.getString(.appVersionAtLastFetchKey, transaction: transaction), - let lastFetchDate = Self.fetcherStore.getDate(.lastFetchDateKey, transaction: transaction) - else { - // If we have never recorded last-fetch data, we should sync. - return true - } - - let hasChangedAppVersion = appVersionAtLastFetch != AppVersionImpl.shared.currentAppVersion - let hasWaitedEnoughSinceLastSync = Date().timeIntervalSince(lastFetchDate) > Self.delayBetweenSyncs - - return hasChangedAppVersion || hasWaitedEnoughSinceLastSync - } - - func recordCompletedSync(transaction: DBWriteTransaction) { - Self.fetcherStore.setString( - AppVersionImpl.shared.currentAppVersion, - key: .appVersionAtLastFetchKey, - transaction: transaction - ) - - Self.fetcherStore.setDate( - Date(), - key: .lastFetchDateKey, - transaction: transaction - ) - } -} - // MARK: - Persisted megaphones private extension RemoteMegaphoneFetcher { diff --git a/SignalServiceKit/Jobs/Cron.swift b/SignalServiceKit/Jobs/Cron.swift index 8c86f4b700..c1185d788e 100644 --- a/SignalServiceKit/Jobs/Cron.swift +++ b/SignalServiceKit/Jobs/Cron.swift @@ -68,6 +68,7 @@ public class Cron { case fetchDevices case fetchEmojiSearch case fetchLocalProfile + case fetchMegaphones case fetchSenderCertificates case fetchStaleGroup case fetchStaleProfiles