import Foundation import TelegramApi import Postbox import SwiftSignalKit import MtProtoKit private typealias SignalKitTimer = SwiftSignalKit.Timer private final class AccountPresenceManagerImpl { private let queue: Queue private let network: Network let isPerformingUpdate = ValuePromise(false, ignoreRepeated: true) private var shouldKeepOnlinePresenceDisposable: Disposable? private let currentRequestDisposable = MetaDisposable() private var onlineTimer: SignalKitTimer? init(queue: Queue, shouldKeepOnlinePresence: Signal, network: Network) { self.queue = queue self.network = network self.shouldKeepOnlinePresenceDisposable = (shouldKeepOnlinePresence |> distinctUntilChanged |> deliverOn(self.queue)).start(next: { [weak self] value in self?.updatePresence(value) }) } deinit { assert(self.queue.isCurrent()) self.shouldKeepOnlinePresenceDisposable?.dispose() self.currentRequestDisposable.dispose() self.onlineTimer?.invalidate() } private func updatePresence(_ isOnline: Bool) { let request: Signal if isOnline { let timer = SignalKitTimer(timeout: 30.0, repeat: false, completion: { [weak self] in guard let strongSelf = self else { return } strongSelf.updatePresence(true) }, queue: self.queue) self.onlineTimer = timer timer.start() request = self.network.request(Api.functions.account.updateStatus(offline: .boolFalse)) } else { self.onlineTimer?.invalidate() self.onlineTimer = nil request = self.network.request(Api.functions.account.updateStatus(offline: .boolTrue)) } self.isPerformingUpdate.set(true) self.currentRequestDisposable.set((request |> `catch` { _ -> Signal in return .single(.boolFalse) } |> deliverOn(self.queue)).start(completed: { [weak self] in guard let strongSelf = self else { return } strongSelf.isPerformingUpdate.set(false) })) } } final class AccountPresenceManager { private let queue = Queue() private let impl: QueueLocalObject init(shouldKeepOnlinePresence: Signal, network: Network) { let queue = self.queue self.impl = QueueLocalObject(queue: self.queue, generate: { return AccountPresenceManagerImpl(queue: queue, shouldKeepOnlinePresence: shouldKeepOnlinePresence, network: network) }) } func isPerformingUpdate() -> Signal { return Signal { subscriber in let disposable = MetaDisposable() self.impl.with { impl in disposable.set(impl.isPerformingUpdate.get().start(next: { value in subscriber.putNext(value) })) } return disposable } } }