refactor on timer and polling threading
This commit is contained in:
parent
eec3d31109
commit
b2ab984586
|
@ -61,13 +61,11 @@ public final class ClosedGroupPoller : NSObject {
|
||||||
|
|
||||||
// MARK: Private API
|
// MARK: Private API
|
||||||
private func setUpPolling(for groupPublicKey: String) {
|
private func setUpPolling(for groupPublicKey: String) {
|
||||||
poll(groupPublicKey).done2 { [weak self] _ in
|
Threading.closedGroupPollerQueue.async {
|
||||||
DispatchQueue.main.async { // Timers don't do well on background queues
|
self.poll(groupPublicKey).done(on: Threading.closedGroupPollerQueue) { [weak self] _ in
|
||||||
self?.pollRecursively(groupPublicKey)
|
self?.pollRecursively(groupPublicKey)
|
||||||
}
|
}.catch(on: Threading.closedGroupPollerQueue) { [weak self] error in
|
||||||
}.catch2 { [weak self] error in
|
// The error is logged in poll(_:)
|
||||||
// The error is logged in poll(_:)
|
|
||||||
DispatchQueue.main.async { // Timers don't do well on background queues
|
|
||||||
self?.pollRecursively(groupPublicKey)
|
self?.pollRecursively(groupPublicKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,18 +85,14 @@ public final class ClosedGroupPoller : NSObject {
|
||||||
let a = (ClosedGroupPoller.maxPollInterval - minPollInterval) / limit
|
let a = (ClosedGroupPoller.maxPollInterval - minPollInterval) / limit
|
||||||
let nextPollInterval = a * min(timeSinceLastMessage, limit) + minPollInterval
|
let nextPollInterval = a * min(timeSinceLastMessage, limit) + minPollInterval
|
||||||
SNLog("Next poll interval for closed group with public key: \(groupPublicKey) is \(nextPollInterval) s.")
|
SNLog("Next poll interval for closed group with public key: \(groupPublicKey) is \(nextPollInterval) s.")
|
||||||
timers[groupPublicKey] = Timer.scheduledTimer(withTimeInterval: nextPollInterval, repeats: false) { [weak self] timer in
|
timers[groupPublicKey] = Timer.scheduledTimerOnMainThread(withTimeInterval: nextPollInterval, repeats: false) { [weak self] timer in
|
||||||
timer.invalidate()
|
timer.invalidate()
|
||||||
Threading.closedGroupPollerQueue.async {
|
Threading.closedGroupPollerQueue.async {
|
||||||
self?.poll(groupPublicKey).done2 { _ in
|
self?.poll(groupPublicKey).done(on: Threading.closedGroupPollerQueue) { _ in
|
||||||
DispatchQueue.main.async { // Timers don't do well on background queues
|
self?.pollRecursively(groupPublicKey)
|
||||||
self?.pollRecursively(groupPublicKey)
|
}.catch(on: Threading.closedGroupPollerQueue) { error in
|
||||||
}
|
|
||||||
}.catch2 { error in
|
|
||||||
// The error is logged in poll(_:)
|
// The error is logged in poll(_:)
|
||||||
DispatchQueue.main.async { // Timers don't do well on background queues
|
self?.pollRecursively(groupPublicKey)
|
||||||
self?.pollRecursively(groupPublicKey)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,18 +19,11 @@ public final class OpenGroupPollerV2 : NSObject {
|
||||||
|
|
||||||
@objc public func startIfNeeded() {
|
@objc public func startIfNeeded() {
|
||||||
guard !hasStarted else { return }
|
guard !hasStarted else { return }
|
||||||
DispatchQueue.main.async { [weak self] in // Timers don't do well on background queues
|
hasStarted = true
|
||||||
guard let strongSelf = self else { return }
|
timer = Timer.scheduledTimerOnMainThread(withTimeInterval: pollInterval, repeats: true) { _ in
|
||||||
strongSelf.hasStarted = true
|
self.poll().retainUntilComplete()
|
||||||
strongSelf.timer = Timer.scheduledTimer(withTimeInterval: strongSelf.pollInterval, repeats: true) { _ in
|
|
||||||
Threading.openGroupPollerQueue.async {
|
|
||||||
self?.poll().retainUntilComplete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Threading.openGroupPollerQueue.async {
|
|
||||||
strongSelf.poll().retainUntilComplete()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
poll().retainUntilComplete()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func stop() {
|
@objc public func stop() {
|
||||||
|
@ -50,15 +43,17 @@ public final class OpenGroupPollerV2 : NSObject {
|
||||||
self.isPolling = true
|
self.isPolling = true
|
||||||
let (promise, seal) = Promise<Void>.pending()
|
let (promise, seal) = Promise<Void>.pending()
|
||||||
promise.retainUntilComplete()
|
promise.retainUntilComplete()
|
||||||
OpenGroupAPIV2.compactPoll(server).done(on: OpenGroupAPIV2.workQueue) { [weak self] bodies in
|
Threading.openGroupPollerQueue.async {
|
||||||
guard let self = self else { return }
|
OpenGroupAPIV2.compactPoll(self.server).done(on: OpenGroupAPIV2.workQueue) { [weak self] bodies in
|
||||||
self.isPolling = false
|
guard let self = self else { return }
|
||||||
bodies.forEach { self.handleCompactPollBody($0, isBackgroundPoll: isBackgroundPoll) }
|
self.isPolling = false
|
||||||
seal.fulfill(())
|
bodies.forEach { self.handleCompactPollBody($0, isBackgroundPoll: isBackgroundPoll) }
|
||||||
}.catch(on: OpenGroupAPIV2.workQueue) { error in
|
seal.fulfill(())
|
||||||
SNLog("Open group polling failed due to error: \(error).")
|
}.catch(on: OpenGroupAPIV2.workQueue) { error in
|
||||||
self.isPolling = false
|
SNLog("Open group polling failed due to error: \(error).")
|
||||||
seal.fulfill(()) // The promise is just used to keep track of when we're done
|
self.isPolling = false
|
||||||
|
seal.fulfill(()) // The promise is just used to keep track of when we're done
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return promise
|
return promise
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,21 +45,22 @@ public final class Poller : NSObject {
|
||||||
// MARK: Private API
|
// MARK: Private API
|
||||||
private func setUpPolling() {
|
private func setUpPolling() {
|
||||||
guard isPolling else { return }
|
guard isPolling else { return }
|
||||||
let _ = SnodeAPI.getSwarm(for: getUserHexEncodedPublicKey()).then2 { [weak self] _ -> Promise<Void> in
|
Threading.pollerQueue.async {
|
||||||
guard let strongSelf = self else { return Promise { $0.fulfill(()) } }
|
let _ = SnodeAPI.getSwarm(for: getUserHexEncodedPublicKey()).then(on: Threading.pollerQueue) { [weak self] _ -> Promise<Void> in
|
||||||
strongSelf.usedSnodes.removeAll()
|
guard let strongSelf = self else { return Promise { $0.fulfill(()) } }
|
||||||
let (promise, seal) = Promise<Void>.pending()
|
strongSelf.usedSnodes.removeAll()
|
||||||
strongSelf.pollNextSnode(seal: seal)
|
let (promise, seal) = Promise<Void>.pending()
|
||||||
return promise
|
strongSelf.pollNextSnode(seal: seal)
|
||||||
}.ensure(on: DispatchQueue.main) { [weak self] in // Timers don't do well on background queues
|
return promise
|
||||||
guard let strongSelf = self, strongSelf.isPolling else { return }
|
}.ensure(on: Threading.pollerQueue) { [weak self] in // Timers don't do well on background queues
|
||||||
Timer.scheduledTimer(withTimeInterval: Poller.retryInterval, repeats: false) { _ in
|
guard let strongSelf = self, strongSelf.isPolling else { return }
|
||||||
guard let strongSelf = self else { return }
|
Timer.scheduledTimerOnMainThread(withTimeInterval: Poller.retryInterval, repeats: false) { _ in
|
||||||
Threading.pollerQueue.async {
|
guard let strongSelf = self else { return }
|
||||||
strongSelf.setUpPolling()
|
strongSelf.setUpPolling()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func pollNextSnode(seal: Resolver<Void>) {
|
private func pollNextSnode(seal: Resolver<Void>) {
|
||||||
|
@ -70,9 +71,9 @@ public final class Poller : NSObject {
|
||||||
// randomElement() uses the system's default random generator, which is cryptographically secure
|
// randomElement() uses the system's default random generator, which is cryptographically secure
|
||||||
let nextSnode = unusedSnodes.randomElement()!
|
let nextSnode = unusedSnodes.randomElement()!
|
||||||
usedSnodes.insert(nextSnode)
|
usedSnodes.insert(nextSnode)
|
||||||
poll(nextSnode, seal: seal).done2 {
|
poll(nextSnode, seal: seal).done(on: Threading.pollerQueue) {
|
||||||
seal.fulfill(())
|
seal.fulfill(())
|
||||||
}.catch2 { [weak self] error in
|
}.catch(on: Threading.pollerQueue) { [weak self] error in
|
||||||
if let error = error as? Error, error == .pollLimitReached {
|
if let error = error as? Error, error == .pollLimitReached {
|
||||||
self?.pollCount = 0
|
self?.pollCount = 0
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,12 +2,13 @@ import PromiseKit
|
||||||
|
|
||||||
/// Delay the execution of the promise constructed in `body` by `delay` seconds.
|
/// Delay the execution of the promise constructed in `body` by `delay` seconds.
|
||||||
public func withDelay<T>(_ delay: TimeInterval, completionQueue: DispatchQueue, body: @escaping () -> Promise<T>) -> Promise<T> {
|
public func withDelay<T>(_ delay: TimeInterval, completionQueue: DispatchQueue, body: @escaping () -> Promise<T>) -> Promise<T> {
|
||||||
#if DEBUG
|
|
||||||
assert(Thread.current.isMainThread) // Timers don't do well on background queues
|
|
||||||
#endif
|
|
||||||
let (promise, seal) = Promise<T>.pending()
|
let (promise, seal) = Promise<T>.pending()
|
||||||
Timer.scheduledTimer(withTimeInterval: delay, repeats: false) { _ in
|
Timer.scheduledTimerOnMainThread(withTimeInterval: delay, repeats: false) { _ in
|
||||||
body().done(on: completionQueue) { seal.fulfill($0) }.catch(on: completionQueue) { seal.reject($0) }
|
body().done(on: completionQueue) {
|
||||||
|
seal.fulfill($0)
|
||||||
|
}.catch(on: completionQueue) {
|
||||||
|
seal.reject($0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return promise
|
return promise
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue