From 5ad32af0d30f5f6130d0abd4a1609bcf3d190969 Mon Sep 17 00:00:00 2001 From: gmbnt Date: Wed, 25 Mar 2020 10:27:43 +1100 Subject: [PATCH] Ditch long polling --- Signal/src/AppDelegate.h | 4 +- Signal/src/AppDelegate.m | 28 +++++----- .../src/Loki/View Controllers/LandingVC.swift | 4 +- .../HomeView/HomeViewController.m | 2 +- ...{LokiLongPoller.swift => LokiPoller.swift} | 51 ++++++++----------- 5 files changed, 41 insertions(+), 48 deletions(-) rename SignalServiceKit/src/Loki/API/{LokiLongPoller.swift => LokiPoller.swift} (53%) diff --git a/Signal/src/AppDelegate.h b/Signal/src/AppDelegate.h index e36cdadca..fe1346722 100644 --- a/Signal/src/AppDelegate.h +++ b/Signal/src/AppDelegate.h @@ -8,8 +8,8 @@ extern NSString *const AppDelegateStoryboardMain; @interface AppDelegate : UIResponder -- (void)startLongPollerIfNeeded; -- (void)stopLongPollerIfNeeded; +- (void)startPollerIfNeeded; +- (void)stopPollerIfNeeded; - (void)setUpDefaultPublicChatsIfNeeded; - (void)startOpenGroupPollersIfNeeded; - (void)stopOpenGroupPollersIfNeeded; diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 19db0cfee..40a825c66 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -69,7 +69,7 @@ static BOOL isInternalTestVersion = NO; // Loki @property (nonatomic) LKP2PServer *lokiP2PServer; -@property (nonatomic) LKLongPoller *lokiLongPoller; +@property (nonatomic) LKPoller *lokiPoller; @property (nonatomic) LKRSSFeedPoller *lokiNewsFeedPoller; @property (nonatomic) LKRSSFeedPoller *lokiMessengerUpdatesFeedPoller; @@ -181,7 +181,7 @@ static BOOL isInternalTestVersion = NO; [DDLog flushLog]; // Loki: Stop pollers - [self stopLongPollerIfNeeded]; + [self stopPollerIfNeeded]; [self stopOpenGroupPollersIfNeeded]; } @@ -202,7 +202,7 @@ static BOOL isInternalTestVersion = NO; [DDLog flushLog]; // Loki: Stop pollers - [self stopLongPollerIfNeeded]; + [self stopPollerIfNeeded]; [self stopOpenGroupPollersIfNeeded]; if (self.lokiP2PServer) { [self.lokiP2PServer stop]; } @@ -784,7 +784,7 @@ static BOOL isInternalTestVersion = NO; [LKP2PAPI broadcastOnlineStatus]; // Loki: Start pollers - [self startLongPollerIfNeeded]; + [self startPollerIfNeeded]; [self startOpenGroupPollersIfNeeded]; // Loki: Get device links @@ -1477,7 +1477,7 @@ static BOOL isInternalTestVersion = NO; [self.lokiFriendRequestExpirationJob startIfNecessary]; // Loki: Start pollers - [self startLongPollerIfNeeded]; + [self startPollerIfNeeded]; [self startOpenGroupPollersIfNeeded]; // Loki: Get device links @@ -1591,12 +1591,12 @@ static BOOL isInternalTestVersion = NO; #pragma mark - Loki -- (void)setUpLongPollerIfNeeded +- (void)setUpPollerIfNeeded { - if (self.lokiLongPoller != nil) { return; } + if (self.lokiPoller != nil) { return; } NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey; if (userHexEncodedPublicKey == nil) { return; } - self.lokiLongPoller = [[LKLongPoller alloc] initOnMessagesReceived:^(NSArray *messages) { + self.lokiPoller = [[LKPoller alloc] initOnMessagesReceived:^(NSArray *messages) { for (SSKProtoEnvelope *message in messages) { NSData *data = [message serializedDataAndReturnError:nil]; if (data != nil) { @@ -1608,15 +1608,15 @@ static BOOL isInternalTestVersion = NO; }]; } -- (void)startLongPollerIfNeeded +- (void)startPollerIfNeeded { - [self setUpLongPollerIfNeeded]; - [self.lokiLongPoller startIfNeeded]; + [self setUpPollerIfNeeded]; + [self.lokiPoller startIfNeeded]; } -- (void)stopLongPollerIfNeeded +- (void)stopPollerIfNeeded { - [self.lokiLongPoller stopIfNeeded]; + [self.lokiPoller stopIfNeeded]; } - (void)setUpDefaultPublicChatsIfNeeded @@ -1713,7 +1713,7 @@ static BOOL isInternalTestVersion = NO; [SSKEnvironment.shared.messageSenderJobQueue clearAllJobs]; [SSKEnvironment.shared.identityManager clearIdentityKey]; [LKAPI clearRandomSnodePool]; - [self stopLongPollerIfNeeded]; + [self stopPollerIfNeeded]; [self stopOpenGroupPollersIfNeeded]; [self.lokiNewsFeedPoller stop]; [self.lokiMessengerUpdatesFeedPoller stop]; diff --git a/Signal/src/Loki/View Controllers/LandingVC.swift b/Signal/src/Loki/View Controllers/LandingVC.swift index 1607ced83..3b8eda399 100644 --- a/Signal/src/Loki/View Controllers/LandingVC.swift +++ b/Signal/src/Loki/View Controllers/LandingVC.swift @@ -155,7 +155,7 @@ final class LandingVC : BaseVC, LinkDeviceVCDelegate, DeviceLinkingModalDelegate TSAccountManager.sharedInstance().phoneNumberAwaitingVerification = keyPair.hexEncodedPublicKey TSAccountManager.sharedInstance().didRegister() let appDelegate = UIApplication.shared.delegate as! AppDelegate - appDelegate.startLongPollerIfNeeded() + appDelegate.startPollerIfNeeded() let deviceLinkingModal = DeviceLinkingModal(mode: .slave, delegate: self) deviceLinkingModal.modalPresentationStyle = .overFullScreen deviceLinkingModal.modalTransitionStyle = .crossDissolve @@ -176,7 +176,7 @@ final class LandingVC : BaseVC, LinkDeviceVCDelegate, DeviceLinkingModalDelegate func handleDeviceLinkingModalDismissed() { let appDelegate = UIApplication.shared.delegate as! AppDelegate - appDelegate.stopLongPollerIfNeeded() + appDelegate.stopPollerIfNeeded() TSAccountManager.sharedInstance().resetForReregistration() } diff --git a/Signal/src/ViewControllers/HomeView/HomeViewController.m b/Signal/src/ViewControllers/HomeView/HomeViewController.m index 6e65a8e0f..80fbf20b2 100644 --- a/Signal/src/ViewControllers/HomeView/HomeViewController.m +++ b/Signal/src/ViewControllers/HomeView/HomeViewController.m @@ -681,7 +681,7 @@ typedef NS_ENUM(NSInteger, HomeViewControllerSection) { [SSKEnvironment.shared.identityManager clearIdentityKey]; [LKAPI clearRandomSnodePool]; AppDelegate *appDelegate = (AppDelegate *)UIApplication.sharedApplication.delegate; - [appDelegate stopLongPollerIfNeeded]; + [appDelegate stopPollerIfNeeded]; [appDelegate stopOpenGroupPollersIfNeeded]; [SSKEnvironment.shared.tsAccountManager resetForReregistration]; UIViewController *rootViewController = [[OnboardingController new] initialViewController]; diff --git a/SignalServiceKit/src/Loki/API/LokiLongPoller.swift b/SignalServiceKit/src/Loki/API/LokiPoller.swift similarity index 53% rename from SignalServiceKit/src/Loki/API/LokiLongPoller.swift rename to SignalServiceKit/src/Loki/API/LokiPoller.swift index f2ee4248e..4b18f1945 100644 --- a/SignalServiceKit/src/Loki/API/LokiLongPoller.swift +++ b/SignalServiceKit/src/Loki/API/LokiPoller.swift @@ -1,20 +1,16 @@ import PromiseKit -@objc(LKLongPoller) -public final class LokiLongPoller : NSObject { +@objc(LKPoller) +public final class LokiPoller : NSObject { private let onMessagesReceived: ([SSKProtoEnvelope]) -> Void private let storage = OWSPrimaryStorage.shared() private var hasStarted = false private var hasStopped = false - private var connections = Set>() private var usedSnodes = Set() // MARK: Settings - private let connectionCount = 3 - private let retryInterval: TimeInterval = 4 - - // MARK: Convenience - private var userHexEncodedPublicKey: String { return getUserHexEncodedPublicKey() } + private static let pollInterval: TimeInterval = 1 + private static let retryInterval: TimeInterval = 4 // MARK: Initialization @objc public init(onMessagesReceived: @escaping ([SSKProtoEnvelope]) -> Void) { @@ -25,7 +21,7 @@ public final class LokiLongPoller : NSObject { // MARK: Public API @objc public func startIfNeeded() { guard !hasStarted else { return } - print("[Loki] Started long polling.") + print("[Loki] Started polling.") hasStarted = true hasStopped = false openConnections() @@ -33,7 +29,7 @@ public final class LokiLongPoller : NSObject { @objc public func stopIfNeeded() { guard !hasStopped else { return } - print("[Loki] Stopped long polling.") + print("[Loki] Stopped polling.") hasStarted = false hasStopped = true usedSnodes.removeAll() @@ -42,49 +38,46 @@ public final class LokiLongPoller : NSObject { // MARK: Private API private func openConnections() { guard !hasStopped else { return } - LokiAPI.getSwarm(for: userHexEncodedPublicKey).then { [weak self] _ -> Guarantee<[Result]> in - guard let strongSelf = self else { return Guarantee.value([Result]()) } + LokiAPI.getSwarm(for: getUserHexEncodedPublicKey()).then { [weak self] _ -> Promise in + guard let strongSelf = self else { return Promise { $0.fulfill(()) } } strongSelf.usedSnodes.removeAll() - let connections: [Promise] = (0...pending() - strongSelf.openConnectionToNextSnode(seal: seal) - return promise - } - strongSelf.connections = Set(connections) - return when(resolved: connections) + let (promise, seal) = Promise.pending() + strongSelf.pollNextSnode(seal: seal) + return promise }.ensure { [weak self] in guard let strongSelf = self else { return } - Timer.scheduledTimer(withTimeInterval: strongSelf.retryInterval, repeats: false) { _ in + Timer.scheduledTimer(withTimeInterval: LokiPoller.retryInterval, repeats: false) { _ in guard let strongSelf = self else { return } strongSelf.openConnections() } } } - private func openConnectionToNextSnode(seal: Resolver) { + private func pollNextSnode(seal: Resolver) { + let userHexEncodedPublicKey = getUserHexEncodedPublicKey() let swarm = LokiAPI.swarmCache[userHexEncodedPublicKey] ?? [] - let userHexEncodedPublicKey = self.userHexEncodedPublicKey let unusedSnodes = Set(swarm).subtracting(usedSnodes) if !unusedSnodes.isEmpty { + // randomElement() uses the system's default random generator, which is cryptographically secure let nextSnode = unusedSnodes.randomElement()! usedSnodes.insert(nextSnode) - print("[Loki] Opening long polling connection to \(nextSnode).") - longPoll(nextSnode, seal: seal).catch(on: LokiAPI.errorHandlingQueue) { [weak self] error in - print("[Loki] Long polling connection to \(nextSnode) failed; dropping it and switching to next snode.") + print("[Loki] Polling \(nextSnode).") + poll(nextSnode, seal: seal).catch(on: LokiAPI.errorHandlingQueue) { [weak self] error in + print("[Loki] Polling \(nextSnode) failed; dropping it and switching to next snode.") LokiAPI.dropIfNeeded(nextSnode, hexEncodedPublicKey: userHexEncodedPublicKey) - self?.openConnectionToNextSnode(seal: seal) + self?.pollNextSnode(seal: seal) } } else { seal.fulfill(()) } } - private func longPoll(_ target: LokiAPITarget, seal: Resolver) -> Promise { - return LokiAPI.getRawMessages(from: target, usingLongPolling: true).then(on: DispatchQueue.global()) { [weak self] rawResponse -> Promise in + private func poll(_ target: LokiAPITarget, seal: Resolver) -> Promise { + return LokiAPI.getRawMessages(from: target, usingLongPolling: false).then(on: DispatchQueue.global()) { [weak self] rawResponse -> Promise in guard let strongSelf = self, !strongSelf.hasStopped else { return Promise.value(()) } let messages = LokiAPI.parseRawMessagesResponse(rawResponse, from: target) strongSelf.onMessagesReceived(messages) - return strongSelf.longPoll(target, seal: seal) + return strongSelf.poll(target, seal: seal) } } }