Ditch long polling

This commit is contained in:
gmbnt 2020-03-25 10:27:43 +11:00
parent 7d507ba3ad
commit 5ad32af0d3
5 changed files with 41 additions and 48 deletions

View File

@ -8,8 +8,8 @@ extern NSString *const AppDelegateStoryboardMain;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
- (void)startLongPollerIfNeeded;
- (void)stopLongPollerIfNeeded;
- (void)startPollerIfNeeded;
- (void)stopPollerIfNeeded;
- (void)setUpDefaultPublicChatsIfNeeded;
- (void)startOpenGroupPollersIfNeeded;
- (void)stopOpenGroupPollersIfNeeded;

View File

@ -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<SSKProtoEnvelope *> *messages) {
self.lokiPoller = [[LKPoller alloc] initOnMessagesReceived:^(NSArray<SSKProtoEnvelope *> *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];

View File

@ -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()
}

View File

@ -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];

View File

@ -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<Promise<Void>>()
private var usedSnodes = Set<LokiAPITarget>()
// 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<Void>]> in
guard let strongSelf = self else { return Guarantee.value([Result<Void>]()) }
LokiAPI.getSwarm(for: getUserHexEncodedPublicKey()).then { [weak self] _ -> Promise<Void> in
guard let strongSelf = self else { return Promise { $0.fulfill(()) } }
strongSelf.usedSnodes.removeAll()
let connections: [Promise<Void>] = (0..<strongSelf.connectionCount).map { _ in
let (promise, seal) = Promise<Void>.pending()
strongSelf.openConnectionToNextSnode(seal: seal)
return promise
}
strongSelf.connections = Set(connections)
return when(resolved: connections)
let (promise, seal) = Promise<Void>.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<Void>) {
private func pollNextSnode(seal: Resolver<Void>) {
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<Void>) -> Promise<Void> {
return LokiAPI.getRawMessages(from: target, usingLongPolling: true).then(on: DispatchQueue.global()) { [weak self] rawResponse -> Promise<Void> in
private func poll(_ target: LokiAPITarget, seal: Resolver<Void>) -> Promise<Void> {
return LokiAPI.getRawMessages(from: target, usingLongPolling: false).then(on: DispatchQueue.global()) { [weak self] rawResponse -> Promise<Void> 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)
}
}
}