mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
More robust presence management
This commit is contained in:
@@ -73,6 +73,8 @@
|
||||
D001F3F61E128A1C007A8C60 /* PendingMessageUploadedContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09BB6B51DB0428000A905C0 /* PendingMessageUploadedContent.swift */; };
|
||||
D001F3F71E128A1C007A8C60 /* ApplyUpdateMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC9221DD5E9A200E8160F /* ApplyUpdateMessage.swift */; };
|
||||
D003702B1DA42586004308D3 /* PhoneNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = D003702A1DA42586004308D3 /* PhoneNumber.swift */; };
|
||||
D00422D321677F4500719B67 /* ManagedAccountPresence.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00422D221677F4500719B67 /* ManagedAccountPresence.swift */; };
|
||||
D00422D421677F4500719B67 /* ManagedAccountPresence.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00422D221677F4500719B67 /* ManagedAccountPresence.swift */; };
|
||||
D00BDA191EE593D600C64C5E /* TelegramChannelAdminRights.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00BDA181EE593D600C64C5E /* TelegramChannelAdminRights.swift */; };
|
||||
D00BDA1A1EE593D600C64C5E /* TelegramChannelAdminRights.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00BDA181EE593D600C64C5E /* TelegramChannelAdminRights.swift */; };
|
||||
D00BDA1C1EE5952A00C64C5E /* TelegramChannelBannedRights.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00BDA1B1EE5952A00C64C5E /* TelegramChannelBannedRights.swift */; };
|
||||
@@ -779,6 +781,7 @@
|
||||
C2FD33E31E687BF1008D13D4 /* PeerPhotoUpdater.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerPhotoUpdater.swift; sourceTree = "<group>"; };
|
||||
C2FD33EA1E696C78008D13D4 /* GroupsInCommon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupsInCommon.swift; sourceTree = "<group>"; };
|
||||
D003702A1DA42586004308D3 /* PhoneNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhoneNumber.swift; sourceTree = "<group>"; };
|
||||
D00422D221677F4500719B67 /* ManagedAccountPresence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedAccountPresence.swift; sourceTree = "<group>"; };
|
||||
D00BDA181EE593D600C64C5E /* TelegramChannelAdminRights.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramChannelAdminRights.swift; sourceTree = "<group>"; };
|
||||
D00BDA1B1EE5952A00C64C5E /* TelegramChannelBannedRights.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramChannelBannedRights.swift; sourceTree = "<group>"; };
|
||||
D00C7CCB1E3620C30080C3D5 /* CachedChannelParticipants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachedChannelParticipants.swift; sourceTree = "<group>"; };
|
||||
@@ -1467,6 +1470,7 @@
|
||||
D048B4AB20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift */,
|
||||
D0467D0A20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift */,
|
||||
D0467D1420D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift */,
|
||||
D00422D221677F4500719B67 /* ManagedAccountPresence.swift */,
|
||||
);
|
||||
name = State;
|
||||
sourceTree = "<group>";
|
||||
@@ -2209,6 +2213,7 @@
|
||||
D0DA1D321F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift in Sources */,
|
||||
D099D7491EEF418D00A3128C /* HistoryViewChannelStateValidation.swift in Sources */,
|
||||
C23BC3871E9BE3CA00D79F92 /* ImportContact.swift in Sources */,
|
||||
D00422D321677F4500719B67 /* ManagedAccountPresence.swift in Sources */,
|
||||
D03B0D0A1D62255C00955575 /* Holes.swift in Sources */,
|
||||
D05464972073872C002ECC1E /* SecureIdBankStatementValue.swift in Sources */,
|
||||
D0B843CB1DA7FF30005F29E1 /* NBPhoneNumberUtil.m in Sources */,
|
||||
@@ -2747,6 +2752,7 @@
|
||||
D0575AF21E9FFA5D006F2541 /* SynchronizeSavedGifsOperation.swift in Sources */,
|
||||
D0528E661E65C82400E2FEF5 /* UpdateContactName.swift in Sources */,
|
||||
D0EE7FC82098853100981319 /* SecureIdTemporaryRegistrationValue.swift in Sources */,
|
||||
D00422D421677F4500719B67 /* ManagedAccountPresence.swift in Sources */,
|
||||
D023E67921540624008C27D1 /* UpdateMessageMedia.swift in Sources */,
|
||||
D053B4191F18DE5000E2D58A /* AuthorSignatureMessageAttribute.swift in Sources */,
|
||||
D0F7B1E81E045C87007EB8A5 /* PeerParticipants.swift in Sources */,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
98
TelegramCore/ManagedAccountPresence.swift
Normal file
98
TelegramCore/ManagedAccountPresence.swift
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user