Fix loading foreign channels

This commit is contained in:
Ali 2021-07-02 16:16:36 +04:00
parent eb480074fd
commit a6955ea613
6 changed files with 114 additions and 61 deletions

View File

@ -904,20 +904,20 @@ public final class MessageHistoryView {
public let isLoading: Bool
public let isAddedToChatList: Bool
public init(tagMask: MessageTags?, namespaces: MessageIdNamespaces, entries: [MessageHistoryEntry], holeEarlier: Bool) {
public init(tagMask: MessageTags?, namespaces: MessageIdNamespaces, entries: [MessageHistoryEntry], holeEarlier: Bool, holeLater: Bool, isLoading: Bool) {
self.tagMask = tagMask
self.namespaces = namespaces
self.anchorIndex = .lowerBound
self.earlierId = nil
self.laterId = nil
self.holeEarlier = holeEarlier
self.holeLater = false
self.holeLater = holeLater
self.entries = entries
self.maxReadIndex = nil
self.fixedReadStates = nil
self.topTaggedMessages = []
self.additionalData = []
self.isLoading = false
self.isLoading = isLoading
self.isAddedToChatList = false
}

View File

@ -1172,7 +1172,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
#if DEBUG
//debugSaveState(basePath: basePath, name: "previous1")
//debugRestoreState(basePath: basePath, name: "previous1")
debugRestoreState(basePath: basePath, name: "previous1")
#endif
let startTime = CFAbsoluteTimeGetCurrent()

View File

@ -1676,49 +1676,49 @@ private func resolveMissingPeerChatInfos(network: Network, state: AccountMutable
}
}
func keepPollingChannel(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager) -> Signal<Void, NoError> {
let signal: Signal<Void, NoError> = postbox.transaction { transaction -> Signal<Void, NoError> in
if let accountState = (transaction.getState() as? AuthorizedAccountState)?.state, let peer = transaction.getPeer(peerId) {
var channelStates: [PeerId: AccountStateChannelState] = [:]
if let channelState = transaction.getPeerChatState(peerId) as? ChannelState {
channelStates[peerId] = AccountStateChannelState(pts: channelState.pts)
}
let initialPeers: [PeerId: Peer] = [peerId: peer]
var peerChatInfos: [PeerId: PeerChatInfo] = [:]
let inclusion = transaction.getPeerChatListInclusion(peerId)
var hasValidInclusion = false
switch inclusion {
case .ifHasMessagesOrOneOf:
hasValidInclusion = true
case .notIncluded:
hasValidInclusion = false
}
if hasValidInclusion {
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
}
}
let initialState = AccountMutableState(initialState: AccountInitialState(state: accountState, peerIds: Set(), peerIdsRequiringLocalChatState: Set(), channelStates: channelStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: [:], cloudReadStates: [:], channelsToPollExplicitely: Set()), initialPeers: initialPeers, initialReferencedMessageIds: Set(), initialStoredMessages: Set(), initialReadInboxMaxIds: [:], storedMessagesByPeerIdAndTimestamp: [:])
return pollChannel(network: network, peer: peer, state: initialState)
|> mapToSignal { (finalState, _, timeout) -> Signal<Void, NoError> in
return resolveAssociatedMessages(network: network, state: finalState)
|> mapToSignal { resultingState -> Signal<AccountFinalState, NoError> in
return resolveMissingPeerChatInfos(network: network, state: resultingState)
|> map { resultingState, _ -> AccountFinalState in
return AccountFinalState(state: resultingState, shouldPoll: false, incomplete: false, missingUpdatesFromChannels: Set(), discard: false)
}
}
|> mapToSignal { finalState -> Signal<Void, NoError> in
return stateManager.addReplayAsynchronouslyBuiltFinalState(finalState)
|> mapToSignal { _ -> Signal<Void, NoError> in
return .complete() |> delay(Double(timeout ?? 30), queue: Queue.concurrentDefaultQueue())
}
}
}
} else {
func keepPollingChannel(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager) -> Signal<Int32, NoError> {
let signal: Signal<Int32, NoError> = postbox.transaction { transaction -> Signal<Int32, NoError> in
guard let accountState = (transaction.getState() as? AuthorizedAccountState)?.state, let peer = transaction.getPeer(peerId) else {
return .complete()
|> delay(30.0, queue: Queue.concurrentDefaultQueue())
}
var channelStates: [PeerId: AccountStateChannelState] = [:]
if let channelState = transaction.getPeerChatState(peerId) as? ChannelState {
channelStates[peerId] = AccountStateChannelState(pts: channelState.pts)
}
let initialPeers: [PeerId: Peer] = [peerId: peer]
var peerChatInfos: [PeerId: PeerChatInfo] = [:]
let inclusion = transaction.getPeerChatListInclusion(peerId)
var hasValidInclusion = false
switch inclusion {
case .ifHasMessagesOrOneOf:
hasValidInclusion = true
case .notIncluded:
hasValidInclusion = false
}
if hasValidInclusion {
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
}
}
let initialState = AccountMutableState(initialState: AccountInitialState(state: accountState, peerIds: Set(), peerIdsRequiringLocalChatState: Set(), channelStates: channelStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: [:], cloudReadStates: [:], channelsToPollExplicitely: Set()), initialPeers: initialPeers, initialReferencedMessageIds: Set(), initialStoredMessages: Set(), initialReadInboxMaxIds: [:], storedMessagesByPeerIdAndTimestamp: [:])
return pollChannel(network: network, peer: peer, state: initialState)
|> mapToSignal { (finalState, _, timeout) -> Signal<Int32, NoError> in
return resolveAssociatedMessages(network: network, state: finalState)
|> mapToSignal { resultingState -> Signal<AccountFinalState, NoError> in
return resolveMissingPeerChatInfos(network: network, state: resultingState)
|> map { resultingState, _ -> AccountFinalState in
return AccountFinalState(state: resultingState, shouldPoll: false, incomplete: false, missingUpdatesFromChannels: Set(), discard: false)
}
}
|> mapToSignal { finalState -> Signal<Int32, NoError> in
return stateManager.addReplayAsynchronouslyBuiltFinalState(finalState)
|> mapToSignal { _ -> Signal<Int32, NoError> in
return .single(timeout ?? 30) |> then(.complete() |> delay(Double(timeout ?? 30), queue: Queue.concurrentDefaultQueue()))
}
}
}
}
|> switchToLatest
|> restart

View File

@ -224,9 +224,21 @@ private final class CachedChannelParticipantsContext {
private final class ChannelPollingContext {
var subscribers = Bag<Void>()
let disposable = MetaDisposable()
let isUpdated = Promise<Bool>(false)
private(set) var isUpdatedValue: Bool = false
private var isUpdatedDisposable: Disposable?
init(queue: Queue) {
self.isUpdatedDisposable = (self.isUpdated.get()
|> deliverOn(queue)).start(next: { [weak self] value in
self?.isUpdatedValue = value
})
}
deinit {
self.disposable.dispose()
self.isUpdatedDisposable?.dispose()
}
}
@ -1302,13 +1314,27 @@ public final class AccountViewTracker {
if let current = self.channelPollingContexts[peerId] {
context = current
} else {
context = ChannelPollingContext()
context = ChannelPollingContext(queue: self.queue)
self.channelPollingContexts[peerId] = context
}
if context.subscribers.isEmpty {
if let account = self.account {
context.disposable.set(keepPollingChannel(postbox: account.postbox, network: account.network, peerId: peerId, stateManager: account.stateManager).start())
let queue = self.queue
context.disposable.set(keepPollingChannel(postbox: account.postbox, network: account.network, peerId: peerId, stateManager: account.stateManager).start(next: { [weak context] isValidForTimeout in
queue.async {
guard let context = context else {
return
}
context.isUpdated.set(
.single(true)
|> then(
.single(false)
|> delay(Double(isValidForTimeout), queue: queue)
)
)
}
}))
}
}
@ -1378,34 +1404,54 @@ public final class AccountViewTracker {
peerId = peerIdValue
}
if peerId.namespace == Namespaces.Peer.CloudChannel {
return Signal { subscriber in
return Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { subscriber in
let combinedDisposable = MetaDisposable()
self.queue.async {
let polled = self.polledChannel(peerId: peerId).start()
var addHole = false
let historyIsValid: Signal<Bool, NoError>
if let context = self.channelPollingContexts[peerId] {
if context.subscribers.isEmpty {
if !context.isUpdatedValue {
addHole = true
}
historyIsValid = context.isUpdated.get()
} else {
addHole = true
historyIsValid = .single(true)
}
if addHole {
let _ = self.account?.postbox.transaction({ transaction -> Void in
if transaction.getPeerChatListIndex(peerId) == nil {
if let message = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud) {
//transaction.addHole(peerId: peerId, namespace: Namespaces.Message.Cloud, space: .everywhere, range: message.id + 1 ... (Int32.max - 1))
}
transaction.addHole(peerId: peerId, namespace: Namespaces.Message.Cloud, space: .everywhere, range: 1 ... (Int32.max - 1))
}
}).start()
}
let disposable = history.start(next: { next in
let validHistory = historyIsValid
|> distinctUntilChanged
|> take(until: { next in
if next {
return SignalTakeAction(passthrough: true, complete: true)
} else {
return SignalTakeAction(passthrough: true, complete: false)
}
})
|> mapToSignal { isValid -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> in
if isValid {
return history
} else {
let view = MessageHistoryView(tagMask: nil, namespaces: .all, entries: [], holeEarlier: true, holeLater: true, isLoading: true)
return .single((view, .Initial, nil))
}
}
let disposable = validHistory.start(next: { next in
subscriber.putNext(next)
}, error: { error in
subscriber.putError(error)
}, completed: {
subscriber.putCompletion()
})
let polled = self.polledChannel(peerId: peerId).start()
combinedDisposable.set(ActionDisposable {
disposable.dispose()
polled.dispose()

View File

@ -750,7 +750,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
scrollPosition = nil
}
return (ChatHistoryViewUpdate.HistoryView(view: MessageHistoryView(tagMask: nil, namespaces: .all, entries: messages.reversed().map { MessageHistoryEntry(message: $0, isRead: false, location: nil, monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false)) }, holeEarlier: hasMore), type: .Generic(type: ViewUpdateType.Initial), scrollPosition: scrollPosition, flashIndicators: false, originalScrollPosition: nil, initialData: ChatHistoryCombinedInitialData(initialData: nil, buttonKeyboardMessage: nil, cachedData: nil, cachedDataMessages: nil, readStateData: nil), id: 0), version, nil)
return (ChatHistoryViewUpdate.HistoryView(view: MessageHistoryView(tagMask: nil, namespaces: .all, entries: messages.reversed().map { MessageHistoryEntry(message: $0, isRead: false, location: nil, monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false)) }, holeEarlier: hasMore, holeLater: false, isLoading: false), type: .Generic(type: ViewUpdateType.Initial), scrollPosition: scrollPosition, flashIndicators: false, originalScrollPosition: nil, initialData: ChatHistoryCombinedInitialData(initialData: nil, buttonKeyboardMessage: nil, cachedData: nil, cachedDataMessages: nil, readStateData: nil), id: 0), version, nil)
}
} else {
historyViewUpdate = self.chatHistoryLocationPromise.get()
@ -906,9 +906,9 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
let historyView = (strongSelf.opaqueTransactionState as? ChatHistoryTransactionOpaqueState)?.historyView
let displayRange = strongSelf.displayedItemRange
if let filteredEntries = historyView?.filteredEntries, let visibleRange = displayRange.visibleRange {
let lastEntry = filteredEntries[filteredEntries.count - 1 - visibleRange.lastIndex]
let firstEntry = filteredEntries[filteredEntries.count - 1 - visibleRange.firstIndex]
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .message(lastEntry.index), anchorIndex: .message(lastEntry.index), count: historyMessageCount, highlight: false), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .message(firstEntry.index), anchorIndex: .message(firstEntry.index), count: historyMessageCount, highlight: false), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)
} else {
if let subject = subject, case let .message(messageId, highlight) = subject {
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60, highlight: highlight), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)

View File

@ -93,13 +93,15 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: A
let (cachedData, cachedDataMessages, readStateData) = extractAdditionalData(view: view, chatLocation: chatLocation)
let combinedInitialData = ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData)
if view.isLoading {
preloaded = false
return .Loading(initialData: combinedInitialData, type: .Generic(type: updateType))
}
if preloaded {
return .HistoryView(view: view, type: .Generic(type: updateType), scrollPosition: nil, flashIndicators: false, originalScrollPosition: nil, initialData: combinedInitialData, id: location.id)
} else {
if view.isLoading {
return .Loading(initialData: combinedInitialData, type: .Generic(type: updateType))
}
var scrollPosition: ChatHistoryViewScrollPosition?
let canScrollToRead: Bool
@ -179,6 +181,11 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: A
let (cachedData, cachedDataMessages, readStateData) = extractAdditionalData(view: view, chatLocation: chatLocation)
let combinedInitialData = ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData)
if view.isLoading {
preloaded = false
return .Loading(initialData: combinedInitialData, type: .Generic(type: updateType))
}
if preloaded {
return .HistoryView(view: view, type: .Generic(type: updateType), scrollPosition: nil, flashIndicators: false, originalScrollPosition: nil, initialData: combinedInitialData, id: location.id)