More robust presence management

This commit is contained in:
Peter
2018-10-06 01:18:17 +04:00
parent 7929819c87
commit 48cb4942c6
5 changed files with 147 additions and 38 deletions

View File

@@ -874,10 +874,10 @@ public class Account {
private(set) var mediaReferenceRevalidationContext: MediaReferenceRevalidationContext!
private var peerInputActivityManager: PeerInputActivityManager!
private var localInputActivityManager: PeerInputActivityManager!
private var accountPresenceManager: AccountPresenceManager!
fileprivate let managedContactsDisposable = MetaDisposable()
fileprivate let managedStickerPacksDisposable = MetaDisposable()
private let becomeMasterDisposable = MetaDisposable()
private let updatedPresenceDisposable = MetaDisposable()
private let managedServiceViewsDisposable = MetaDisposable()
private let managedOperationsDisposable = DisposableSet()
@@ -948,6 +948,8 @@ public class Account {
self?.stateManager.addUpdates(updates)
})
self.localInputActivityManager = PeerInputActivityManager()
self.accountPresenceManager = AccountPresenceManager(shouldKeepOnlinePresence: self.shouldKeepOnlinePresence.get(), network: network)
self.viewTracker = AccountViewTracker(account: self)
self.messageMediaPreuploadManager = MessageMediaPreuploadManager()
self.mediaReferenceRevalidationContext = MediaReferenceRevalidationContext()
@@ -1146,16 +1148,17 @@ public class Account {
let importantBackgroundOperations: [Signal<AccountRunningImportantTasks, NoError>] = [
managedSynchronizeChatInputStateOperations(postbox: self.postbox, network: self.network) |> map { $0 ? AccountRunningImportantTasks.other : [] },
self.pendingMessageManager.hasPendingMessages |> map { $0 ? AccountRunningImportantTasks.pendingMessages : [] }
self.pendingMessageManager.hasPendingMessages |> map { $0 ? AccountRunningImportantTasks.pendingMessages : [] },
self.accountPresenceManager.isPerformingUpdate() |> map { $0 ? AccountRunningImportantTasks.other : [] }
]
let importantBackgroundOperationsRunning = combineLatest(importantBackgroundOperations)
|> deliverOn(Queue())
|> map { values -> AccountRunningImportantTasks in
var result: AccountRunningImportantTasks = []
for value in values {
result.formUnion(value)
}
return result
|> deliverOn(Queue())
|> map { values -> AccountRunningImportantTasks in
var result: AccountRunningImportantTasks = []
for value in values {
result.formUnion(value)
}
return result
}
self.managedOperationsDisposable.add(importantBackgroundOperationsRunning.start(next: { [weak self] value in
@@ -1170,32 +1173,38 @@ public class Account {
self.managedOperationsDisposable.add(managedLocalizationUpdatesOperations(postbox: self.postbox, network: self.network).start())
self.managedOperationsDisposable.add(managedPendingPeerNotificationSettings(postbox: self.postbox, network: self.network).start())
let updatedPresence = self.shouldKeepOnlinePresence.get()
|> distinctUntilChanged
|> mapToSignal { [weak self] online -> Signal<Void, NoError> in
if let strongSelf = self {
let delayRequest: Signal<Void, NoError> = .complete() |> delay(60.0, queue: Queue.concurrentDefaultQueue())
let pushStatusOnce = strongSelf.network.request(Api.functions.account.updateStatus(offline: online ? .boolFalse : .boolTrue))
|> retryRequest
|> mapToSignal { _ -> Signal<Void, NoError> in return .complete() }
let pushStatusRepeatedly = (pushStatusOnce |> then(delayRequest)) |> restart
let peerId = strongSelf.peerId
let updatePresenceLocally = strongSelf.postbox.transaction { transaction -> Void in
let timestamp: Double
if online {
timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60.0 * 60.0 * 24.0 * 356.0
} else {
timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - 1.0
}
transaction.updatePeerPresences([peerId: TelegramUserPresence(status: .present(until: Int32(timestamp)))])
/*let updatedPresence = self.shouldKeepOnlinePresence.get()
|> distinctUntilChanged
|> mapToSignal { [weak self] online -> Signal<Void, NoError> in
if let strongSelf = self {
let delayRequest: Signal<Void, NoError> = .complete()
|> delay(60.0, queue: Queue.concurrentDefaultQueue())
let pushStatusOnce = strongSelf.network.request(Api.functions.account.updateStatus(offline: online ? .boolFalse : .boolTrue))
|> retryRequest
|> mapToSignal { _ -> Signal<Void, NoError> in return .complete() }
let pushStatusRepeatedly = (pushStatusOnce
|> then(delayRequest))
|> restart
let peerId = strongSelf.peerId
let updatePresenceLocally = strongSelf.postbox.transaction { transaction -> Void in
let timestamp: Double
if online {
timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60.0 * 60.0 * 24.0 * 356.0
} else {
timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - 1.0
}
return combineLatest(pushStatusRepeatedly, updatePresenceLocally)
|> mapToSignal { _ -> Signal<Void, NoError> in return .complete() }
} else {
return .complete()
transaction.updatePeerPresences([peerId: TelegramUserPresence(status: .present(until: Int32(timestamp)))])
}
return combineLatest(pushStatusRepeatedly, updatePresenceLocally)
|> mapToSignal { _ -> Signal<Void, NoError> in return .complete()
}
} else {
return .complete()
}
}
self.updatedPresenceDisposable.set(updatedPresence.start())
self.updatedPresenceDisposable.set(updatedPresence.start())*/
}
deinit {
@@ -1204,7 +1213,6 @@ public class Account {
self.notificationTokenDisposable.dispose()
self.voipTokenDisposable.dispose()
self.managedServiceViewsDisposable.dispose()
self.updatedPresenceDisposable.dispose()
self.managedOperationsDisposable.dispose()
}

View File

@@ -157,7 +157,7 @@ struct AccountMutableState {
self.preCachedResources.append(contentsOf: other.preCachedResources)
for (peerId, namespaces) in other.namespacesWithHolesFromPreviousState {
if self.namespacesWithHolesFromPreviousState[peerId] == nil {
self.self.namespacesWithHolesFromPreviousState[peerId] = Set()
self.namespacesWithHolesFromPreviousState[peerId] = Set()
}
for namespace in namespaces {
self.namespacesWithHolesFromPreviousState[peerId]!.insert(namespace)

View File

@@ -1593,10 +1593,7 @@ private func resetChannels(_ account: Account, peers: [Peer], state: AccountMuta
private func pollChannel(_ account: Account, peer: Peer, state: AccountMutableState) -> Signal<(AccountMutableState, Bool, Int32?), NoError> {
if let inputChannel = apiInputChannel(peer) {
var limit: Int32 = 20
#if (arch(i386) || arch(x86_64)) && os(iOS)
limit = 3
#endif
let limit: Int32 = 20
let pollPts: Int32
if let channelState = state.chatStates[peer.id] as? ChannelState {
pollPts = channelState.pts

View File

@@ -0,0 +1,98 @@
import Foundation
#if os(macOS)
import PostboxMac
import SwiftSignalKitMac
import MtProtoKitMac
#else
import Postbox
import SwiftSignalKit
import MtProtoKitDynamic
#endif
#if os(macOS)
private typealias SignalKitTimer = SwiftSignalKitMac.Timer
#else
private typealias SignalKitTimer = SwiftSignalKit.Timer
#endif
private final class AccountPresenceManagerImpl {
private let queue: Queue
private let network: Network
let isPerformingUpdate = ValuePromise<Bool>(false, ignoreRepeated: true)
private var shouldKeepOnlinePresenceDisposable: Disposable?
private let currentRequestDisposable = MetaDisposable()
private var onlineTimer: SignalKitTimer?
init(queue: Queue, shouldKeepOnlinePresence: Signal<Bool, NoError>, 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<Api.Bool, MTRpcError>
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<Api.Bool, NoError> 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<AccountPresenceManagerImpl>
init(shouldKeepOnlinePresence: Signal<Bool, NoError>, network: Network) {
let queue = self.queue
self.impl = QueueLocalObject(queue: self.queue, generate: {
return AccountPresenceManagerImpl(queue: queue, shouldKeepOnlinePresence: shouldKeepOnlinePresence, network: network)
})
}
func isPerformingUpdate() -> Signal<Bool, NoError> {
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
}
}
}