mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-19 12:10:55 +00:00
Bug fixes in message history view
This commit is contained in:
parent
1739bf14ff
commit
36aaf31045
@ -143,6 +143,10 @@ public struct MessageIndex: Comparable, Hashable {
|
|||||||
return MessageIndex(id: MessageId(peerId: peerId, namespace: self.id.namespace, id: self.id.id), timestamp: self.timestamp)
|
return MessageIndex(id: MessageId(peerId: peerId, namespace: self.id.namespace, id: self.id.id), timestamp: self.timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func withNamespace(_ namespace: MessageId.Namespace) -> MessageIndex {
|
||||||
|
return MessageIndex(id: MessageId(peerId: self.id.peerId, namespace: namespace, id: self.id.id), timestamp: self.timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
public static func <(lhs: MessageIndex, rhs: MessageIndex) -> Bool {
|
public static func <(lhs: MessageIndex, rhs: MessageIndex) -> Bool {
|
||||||
if lhs.timestamp != rhs.timestamp {
|
if lhs.timestamp != rhs.timestamp {
|
||||||
return lhs.timestamp < rhs.timestamp
|
return lhs.timestamp < rhs.timestamp
|
||||||
|
@ -2358,21 +2358,31 @@ final class MessageHistoryTable: Table {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func findClosestMessageId(peerId: PeerId, namespace: MessageId.Namespace, timestamp: Int32) -> MessageId? {
|
func findClosestMessageIndex(peerId: PeerId, timestamp: Int32) -> MessageIndex? {
|
||||||
var result: MessageId?
|
var closestIndex: MessageIndex?
|
||||||
self.valueBox.range(self.table, start: self.key(MessageIndex(id: MessageId(peerId: peerId, namespace: namespace, id: 0), timestamp: timestamp)), end: self.lowerBound(peerId: peerId, namespace: namespace), values: { key, value in
|
for namespace in self.messageHistoryIndexTable.existingNamespaces(peerId: peerId) {
|
||||||
let entry = self.readIntermediateEntry(key, value: value)
|
var index: MessageIndex?
|
||||||
result = entry.message.id
|
self.valueBox.range(self.table, start: self.key(MessageIndex(id: MessageId(peerId: peerId, namespace: namespace, id: 0), timestamp: timestamp)), end: self.lowerBound(peerId: peerId, namespace: namespace), keys: { key in
|
||||||
|
index = extractKey(key)
|
||||||
return false
|
return false
|
||||||
}, limit: 1)
|
}, limit: 1)
|
||||||
if result == nil {
|
if index == nil {
|
||||||
self.valueBox.range(self.table, start: self.key(MessageIndex(id: MessageId(peerId: peerId, namespace: namespace, id: 0), timestamp: timestamp)), end: self.upperBound(peerId: peerId, namespace: namespace), values: { key, value in
|
self.valueBox.range(self.table, start: self.key(MessageIndex(id: MessageId(peerId: peerId, namespace: namespace, id: 0), timestamp: timestamp)), end: self.upperBound(peerId: peerId, namespace: namespace), keys: { key in
|
||||||
let entry = self.readIntermediateEntry(key, value: value)
|
index = extractKey(key)
|
||||||
result = entry.message.id
|
|
||||||
return false
|
return false
|
||||||
}, limit: 0)
|
}, limit: 0)
|
||||||
}
|
}
|
||||||
return result
|
if let index = index {
|
||||||
|
if let closestIndexValue = closestIndex {
|
||||||
|
if abs(index.timestamp - timestamp) < abs(closestIndexValue.timestamp - timestamp) {
|
||||||
|
closestIndex = index
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
closestIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return closestIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
func findRandomMessage(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags, ignoreIds: ([MessageId], Set<MessageId>)) -> MessageIndex? {
|
func findRandomMessage(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags, ignoreIds: ([MessageId], Set<MessageId>)) -> MessageIndex? {
|
||||||
@ -2554,6 +2564,8 @@ final class MessageHistoryTable: Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func fetch(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags?, from fromIndex: MessageIndex, includeFrom: Bool, to toIndex: MessageIndex, limit: Int) -> [IntermediateMessage] {
|
func fetch(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags?, from fromIndex: MessageIndex, includeFrom: Bool, to toIndex: MessageIndex, limit: Int) -> [IntermediateMessage] {
|
||||||
|
precondition(fromIndex.id.peerId == toIndex.id.peerId)
|
||||||
|
precondition(fromIndex.id.namespace == toIndex.id.namespace)
|
||||||
var result: [IntermediateMessage] = []
|
var result: [IntermediateMessage] = []
|
||||||
if let tag = tag {
|
if let tag = tag {
|
||||||
let indices: [MessageIndex]
|
let indices: [MessageIndex]
|
||||||
@ -2563,6 +2575,15 @@ final class MessageHistoryTable: Table {
|
|||||||
indices = self.tagsTable.earlierIndices(tag: tag, peerId: peerId, namespace: namespace, index: fromIndex, includeFrom: includeFrom, count: limit)
|
indices = self.tagsTable.earlierIndices(tag: tag, peerId: peerId, namespace: namespace, index: fromIndex, includeFrom: includeFrom, count: limit)
|
||||||
}
|
}
|
||||||
for index in indices {
|
for index in indices {
|
||||||
|
if fromIndex < toIndex {
|
||||||
|
if index < fromIndex || index > toIndex {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if index < toIndex || index > fromIndex {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
if let message = self.getMessage(index) {
|
if let message = self.getMessage(index) {
|
||||||
result.append(message)
|
result.append(message)
|
||||||
} else {
|
} else {
|
||||||
@ -2571,7 +2592,7 @@ final class MessageHistoryTable: Table {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let startKey: ValueBoxKey
|
let startKey: ValueBoxKey
|
||||||
if includeFrom {
|
if includeFrom && fromIndex != MessageIndex.upperBound(peerId: peerId, namespace: namespace) {
|
||||||
if fromIndex < toIndex {
|
if fromIndex < toIndex {
|
||||||
startKey = self.key(fromIndex).predecessor
|
startKey = self.key(fromIndex).predecessor
|
||||||
} else {
|
} else {
|
||||||
@ -2581,7 +2602,9 @@ final class MessageHistoryTable: Table {
|
|||||||
startKey = self.key(fromIndex)
|
startKey = self.key(fromIndex)
|
||||||
}
|
}
|
||||||
self.valueBox.range(self.table, start: startKey, end: self.key(toIndex), values: { key, value in
|
self.valueBox.range(self.table, start: startKey, end: self.key(toIndex), values: { key, value in
|
||||||
result.append(self.readIntermediateEntry(key, value: value).message)
|
let message = self.readIntermediateEntry(key, value: value).message
|
||||||
|
assert(message.id.peerId == peerId && message.id.namespace == namespace)
|
||||||
|
result.append(message)
|
||||||
return true
|
return true
|
||||||
}, limit: limit)
|
}, limit: limit)
|
||||||
}
|
}
|
||||||
|
@ -313,12 +313,13 @@ final class MutableMessageHistoryView {
|
|||||||
self.topTaggedMessages = topTaggedMessages
|
self.topTaggedMessages = topTaggedMessages
|
||||||
self.additionalDatas = additionalDatas
|
self.additionalDatas = additionalDatas
|
||||||
|
|
||||||
self.state = HistoryViewState(postbox: postbox, inputAnchor: inputAnchor, tag: tag, limit: count, locations: peerIds)
|
self.state = HistoryViewState(postbox: postbox, inputAnchor: inputAnchor, tag: tag, limit: count + 2, locations: peerIds)
|
||||||
if case let .loading(loadingState) = self.state {
|
if case let .loading(loadingState) = self.state {
|
||||||
let sampledState = loadingState.checkAndSample(postbox: postbox)
|
let sampledState = loadingState.checkAndSample(postbox: postbox)
|
||||||
switch sampledState {
|
switch sampledState {
|
||||||
case let .ready(anchor, holes):
|
case let .ready(anchor, holes):
|
||||||
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, limit: count, locations: peerIds, postbox: postbox, holes: holes))
|
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, limit: count + 2, locations: peerIds, postbox: postbox, holes: holes))
|
||||||
|
self.sampledState = self.state.sample(postbox: postbox)
|
||||||
case .loadHole:
|
case .loadHole:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -327,12 +328,21 @@ final class MutableMessageHistoryView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func reset(postbox: Postbox) {
|
private func reset(postbox: Postbox) {
|
||||||
self.state = HistoryViewState(postbox: postbox, inputAnchor: self.anchor, tag: self.tag, limit: self.fillCount, locations: self.peerIds)
|
self.state = HistoryViewState(postbox: postbox, inputAnchor: self.anchor, tag: self.tag, limit: self.fillCount + 2, locations: self.peerIds)
|
||||||
if case let .loading(loadingState) = self.state {
|
if case let .loading(loadingState) = self.state {
|
||||||
let sampledState = loadingState.checkAndSample(postbox: postbox)
|
let sampledState = loadingState.checkAndSample(postbox: postbox)
|
||||||
switch sampledState {
|
switch sampledState {
|
||||||
case let .ready(anchor, holes):
|
case let .ready(anchor, holes):
|
||||||
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, limit: self.fillCount, locations: self.peerIds, postbox: postbox, holes: holes))
|
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, limit: self.fillCount + 2, locations: self.peerIds, postbox: postbox, holes: holes))
|
||||||
|
case .loadHole:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if case let .loading(loadingState) = self.state {
|
||||||
|
let sampledState = loadingState.checkAndSample(postbox: postbox)
|
||||||
|
switch sampledState {
|
||||||
|
case let .ready(anchor, holes):
|
||||||
|
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, limit: self.fillCount + 2, locations: self.peerIds, postbox: postbox, holes: holes))
|
||||||
case .loadHole:
|
case .loadHole:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -364,40 +374,63 @@ final class MutableMessageHistoryView {
|
|||||||
|
|
||||||
func replay(postbox: Postbox, transaction: PostboxTransaction, updatedMedia: [MediaId: Media?], updatedCachedPeerData: [PeerId: CachedPeerData], context: MutableMessageHistoryViewReplayContext, renderIntermediateMessage: (IntermediateMessage) -> Message) -> Bool {
|
func replay(postbox: Postbox, transaction: PostboxTransaction, updatedMedia: [MediaId: Media?], updatedCachedPeerData: [PeerId: CachedPeerData], context: MutableMessageHistoryViewReplayContext, renderIntermediateMessage: (IntermediateMessage) -> Message) -> Bool {
|
||||||
var operations: [[MessageHistoryOperation]] = []
|
var operations: [[MessageHistoryOperation]] = []
|
||||||
|
var peerIdsSet = Set<PeerId>()
|
||||||
|
|
||||||
switch self.peerIds {
|
switch self.peerIds {
|
||||||
case let .single(peerId):
|
case let .single(peerId):
|
||||||
|
peerIdsSet.insert(peerId)
|
||||||
if let value = transaction.currentOperationsByPeerId[peerId] {
|
if let value = transaction.currentOperationsByPeerId[peerId] {
|
||||||
operations.append(value)
|
operations.append(value)
|
||||||
}
|
}
|
||||||
case .associated:
|
case .associated:
|
||||||
var ids = Set<PeerId>()
|
|
||||||
switch self.peerIds {
|
switch self.peerIds {
|
||||||
case .single:
|
case .single:
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
case let .associated(mainPeerId, associatedPeerId):
|
case let .associated(mainPeerId, associatedPeerId):
|
||||||
ids.insert(mainPeerId)
|
peerIdsSet.insert(mainPeerId)
|
||||||
if let associatedPeerId = associatedPeerId {
|
if let associatedPeerId = associatedPeerId {
|
||||||
ids.insert(associatedPeerId.peerId)
|
peerIdsSet.insert(associatedPeerId.peerId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ids.isEmpty {
|
|
||||||
for (peerId, value) in transaction.currentOperationsByPeerId {
|
for (peerId, value) in transaction.currentOperationsByPeerId {
|
||||||
if ids.contains(peerId) {
|
if peerIdsSet.contains(peerId) {
|
||||||
operations.append(value)
|
operations.append(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var hasChanges = false
|
var hasChanges = false
|
||||||
|
|
||||||
let unwrappedTag: MessageTags = self.tag ?? []
|
let unwrappedTag: MessageTags = self.tag ?? []
|
||||||
|
|
||||||
switch self.state {
|
switch self.state {
|
||||||
case .loading:
|
case let .loading(loadingState):
|
||||||
break
|
for (key, holeOperations) in transaction.currentPeerHoleOperations {
|
||||||
|
var matchesSpace = false
|
||||||
|
switch key.space {
|
||||||
|
case .everywhere:
|
||||||
|
matchesSpace = unwrappedTag.isEmpty
|
||||||
|
case let .tag(tag):
|
||||||
|
matchesSpace = tag.contains(unwrappedTag)
|
||||||
|
}
|
||||||
|
if matchesSpace {
|
||||||
|
if peerIdsSet.contains(key.peerId) {
|
||||||
|
for operation in holeOperations {
|
||||||
|
switch operation {
|
||||||
|
case let .insert(range):
|
||||||
|
if loadingState.insertHole(space: PeerIdAndNamespace(peerId: key.peerId, namespace: key.namespace), range: range) {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
case let .remove(range):
|
||||||
|
if loadingState.removeHole(space: PeerIdAndNamespace(peerId: key.peerId, namespace: key.namespace), range: range) {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case let .loaded(loadedState):
|
case let .loaded(loadedState):
|
||||||
for operationSet in operations {
|
for operationSet in operations {
|
||||||
for operation in operationSet {
|
for operation in operationSet {
|
||||||
@ -439,9 +472,43 @@ final class MutableMessageHistoryView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (key, holeOperations) in transaction.currentPeerHoleOperations {
|
||||||
|
var matchesSpace = false
|
||||||
|
switch key.space {
|
||||||
|
case .everywhere:
|
||||||
|
matchesSpace = unwrappedTag.isEmpty
|
||||||
|
case let .tag(tag):
|
||||||
|
matchesSpace = tag.contains(unwrappedTag)
|
||||||
|
}
|
||||||
|
if matchesSpace {
|
||||||
|
if peerIdsSet.contains(key.peerId) {
|
||||||
|
for operation in holeOperations {
|
||||||
|
switch operation {
|
||||||
|
case let .insert(range):
|
||||||
|
if loadedState.insertHole(space: PeerIdAndNamespace(peerId: key.peerId, namespace: key.namespace), range: range) {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
case let .remove(range):
|
||||||
|
if loadedState.removeHole(space: PeerIdAndNamespace(peerId: key.peerId, namespace: key.namespace), range: range) {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasChanges {
|
if hasChanges {
|
||||||
|
if case let .loading(loadingState) = self.state {
|
||||||
|
let sampledState = loadingState.checkAndSample(postbox: postbox)
|
||||||
|
switch sampledState {
|
||||||
|
case let .ready(anchor, holes):
|
||||||
|
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, limit: self.fillCount + 2, locations: self.peerIds, postbox: postbox, holes: holes))
|
||||||
|
case .loadHole:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
self.sampledState = self.state.sample(postbox: postbox)
|
self.sampledState = self.state.sample(postbox: postbox)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -799,10 +866,16 @@ public final class MessageHistoryView {
|
|||||||
|
|
||||||
init(_ mutableView: MutableMessageHistoryView) {
|
init(_ mutableView: MutableMessageHistoryView) {
|
||||||
self.tagMask = mutableView.tag
|
self.tagMask = mutableView.tag
|
||||||
switch mutableView.state {
|
var entries: [MessageHistoryEntry]
|
||||||
|
switch mutableView.sampledState {
|
||||||
case .loading:
|
case .loading:
|
||||||
self.isLoading = true
|
self.isLoading = true
|
||||||
self.anchorIndex = .upperBound
|
self.anchorIndex = .upperBound
|
||||||
|
entries = []
|
||||||
|
self.holeEarlier = true
|
||||||
|
self.holeLater = true
|
||||||
|
self.earlierId = nil
|
||||||
|
self.laterId = nil
|
||||||
case let .loaded(state):
|
case let .loaded(state):
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
switch state.anchor {
|
switch state.anchor {
|
||||||
@ -813,7 +886,50 @@ public final class MessageHistoryView {
|
|||||||
case let .index(index):
|
case let .index(index):
|
||||||
self.anchorIndex = .message(index)
|
self.anchorIndex = .message(index)
|
||||||
}
|
}
|
||||||
|
self.holeEarlier = state.holesToLower
|
||||||
|
self.holeLater = state.holesToHigher
|
||||||
|
entries = []
|
||||||
|
if let transientReadStates = mutableView.transientReadStates, case let .peer(states) = transientReadStates {
|
||||||
|
for entry in state.entries {
|
||||||
|
let read: Bool
|
||||||
|
if entry.message.flags.contains(.Incoming) {
|
||||||
|
read = false
|
||||||
|
} else if let readState = states[entry.message.id.peerId] {
|
||||||
|
read = readState.isOutgoingMessageIndexRead(entry.message.index)
|
||||||
|
} else {
|
||||||
|
read = false
|
||||||
}
|
}
|
||||||
|
entries.append(MessageHistoryEntry(message: entry.message, isRead: read, location: entry.location, monthLocation: entry.monthLocation, attributes: entry.attributes))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for entry in state.entries {
|
||||||
|
entries.append(MessageHistoryEntry(message: entry.message, isRead: false, location: entry.location, monthLocation: entry.monthLocation, attributes: entry.attributes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let stableIds = Set(entries.map({ $0.message.stableId }))
|
||||||
|
assert(stableIds.count == entries.count)
|
||||||
|
if !entries.isEmpty {
|
||||||
|
let anchorIndex = binaryIndexOrLower(entries, state.anchor)
|
||||||
|
let lowerCount = mutableView.fillCount / 2 + 1
|
||||||
|
let upperCount = mutableView.fillCount / 2
|
||||||
|
if entries.count - anchorIndex >= upperCount {
|
||||||
|
self.laterId = entries[entries.count - 1].index
|
||||||
|
entries.removeLast()
|
||||||
|
} else {
|
||||||
|
self.laterId = nil
|
||||||
|
}
|
||||||
|
if anchorIndex >= lowerCount {
|
||||||
|
self.earlierId = entries[0].index
|
||||||
|
entries.removeFirst()
|
||||||
|
} else {
|
||||||
|
self.earlierId = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.earlierId = nil
|
||||||
|
self.laterId = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*var entries: [MessageHistoryEntry] = []
|
/*var entries: [MessageHistoryEntry] = []
|
||||||
if let transientReadStates = mutableView.transientReadStates, case let .peer(states) = transientReadStates {
|
if let transientReadStates = mutableView.transientReadStates, case let .peer(states) = transientReadStates {
|
||||||
@ -972,14 +1088,6 @@ public final class MessageHistoryView {
|
|||||||
self.topTaggedMessages = topTaggedMessages
|
self.topTaggedMessages = topTaggedMessages
|
||||||
self.additionalData = mutableView.additionalDatas
|
self.additionalData = mutableView.additionalDatas
|
||||||
|
|
||||||
var entries: [MessageHistoryEntry] = []
|
|
||||||
|
|
||||||
self.entries = entries
|
|
||||||
self.earlierId = nil
|
|
||||||
self.laterId = nil
|
|
||||||
self.holeEarlier = false
|
|
||||||
self.holeLater = false
|
|
||||||
|
|
||||||
self.fixedReadStates = mutableView.combinedReadStates
|
self.fixedReadStates = mutableView.combinedReadStates
|
||||||
|
|
||||||
if let combinedReadStates = mutableView.combinedReadStates {
|
if let combinedReadStates = mutableView.combinedReadStates {
|
||||||
@ -997,14 +1105,14 @@ public final class MessageHistoryView {
|
|||||||
|
|
||||||
if hasUnread {
|
if hasUnread {
|
||||||
var peerIds = Set<PeerId>()
|
var peerIds = Set<PeerId>()
|
||||||
for entry in self.entries {
|
for entry in entries {
|
||||||
peerIds.insert(entry.index.id.peerId)
|
peerIds.insert(entry.index.id.peerId)
|
||||||
}
|
}
|
||||||
for peerId in peerIds {
|
for peerId in peerIds {
|
||||||
if let combinedReadState = states[peerId] {
|
if let combinedReadState = states[peerId] {
|
||||||
for (namespace, state) in combinedReadState.states {
|
for (namespace, state) in combinedReadState.states {
|
||||||
var maxNamespaceIndex: MessageIndex?
|
var maxNamespaceIndex: MessageIndex?
|
||||||
var index = self.entries.count - 1
|
var index = entries.count - 1
|
||||||
for entry in entries.reversed() {
|
for entry in entries.reversed() {
|
||||||
if entry.index.id.peerId == peerId && entry.index.id.namespace == namespace && state.isIncomingMessageIndexRead(entry.index) {
|
if entry.index.id.peerId == peerId && entry.index.id.namespace == namespace && state.isIncomingMessageIndexRead(entry.index) {
|
||||||
maxNamespaceIndex = entry.index
|
maxNamespaceIndex = entry.index
|
||||||
@ -1043,5 +1151,7 @@ public final class MessageHistoryView {
|
|||||||
} else {
|
} else {
|
||||||
self.maxReadIndex = nil
|
self.maxReadIndex = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.entries = entries
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,22 @@ private func binaryInsertionIndex(_ inputArr: [MutableMessageHistoryEntry], sear
|
|||||||
return lo
|
return lo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func binaryIndexOrLower(_ inputArr: [MessageHistoryEntry], _ searchItem: HistoryViewAnchor) -> Int {
|
||||||
|
var lo = 0
|
||||||
|
var hi = inputArr.count - 1
|
||||||
|
while lo <= hi {
|
||||||
|
let mid = (lo + hi) / 2
|
||||||
|
if searchItem.isGreater(than: inputArr[mid].index) {
|
||||||
|
lo = mid + 1
|
||||||
|
} else if searchItem.isLower(than: inputArr[mid].index) {
|
||||||
|
hi = mid - 1
|
||||||
|
} else {
|
||||||
|
return mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hi
|
||||||
|
}
|
||||||
|
|
||||||
private func binaryIndexOrLower(_ inputArr: [MutableMessageHistoryEntry], _ searchItem: HistoryViewAnchor) -> Int {
|
private func binaryIndexOrLower(_ inputArr: [MutableMessageHistoryEntry], _ searchItem: HistoryViewAnchor) -> Int {
|
||||||
var lo = 0
|
var lo = 0
|
||||||
var hi = inputArr.count - 1
|
var hi = inputArr.count - 1
|
||||||
@ -115,9 +131,8 @@ private func sampleEntries(orderedEntriesBySpace: [PeerIdAndNamespace: OrderedHi
|
|||||||
}
|
}
|
||||||
if let minSpace = minSpace {
|
if let minSpace = minSpace {
|
||||||
backwardsResult.append((minSpace, previousAnchorIndices[minSpace]!))
|
backwardsResult.append((minSpace, previousAnchorIndices[minSpace]!))
|
||||||
//result.insert(sortedEntriesBySpace[minSpace]![previousAnchorIndices[minSpace]!], at: 0)
|
|
||||||
previousAnchorIndices[minSpace]! -= 1
|
previousAnchorIndices[minSpace]! -= 1
|
||||||
if result.count == limit {
|
if (result.count + backwardsResult.count) == limit {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,9 +151,8 @@ private func sampleEntries(orderedEntriesBySpace: [PeerIdAndNamespace: OrderedHi
|
|||||||
}
|
}
|
||||||
if let maxSpace = maxSpace {
|
if let maxSpace = maxSpace {
|
||||||
result.append((maxSpace, nextAnchorIndices[maxSpace]!))
|
result.append((maxSpace, nextAnchorIndices[maxSpace]!))
|
||||||
//result.append(sortedEntriesBySpace[maxSpace]![nextAnchorIndices[maxSpace]!])
|
|
||||||
nextAnchorIndices[maxSpace]! += 1
|
nextAnchorIndices[maxSpace]! += 1
|
||||||
if result.count == limit {
|
if (result.count + backwardsResult.count) == limit {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,18 +216,24 @@ private func isIndex(index: MessageIndex, closerTo anchor: HistoryViewAnchor, th
|
|||||||
private func sampleHoleRanges(orderedEntriesBySpace: [PeerIdAndNamespace: OrderedHistoryViewEntries], holes: HistoryViewHoles, anchor: HistoryViewAnchor, tag: MessageTags?) -> (clipRanges: [ClosedRange<MessageIndex>], sampledHole: SampledHistoryViewHole?) {
|
private func sampleHoleRanges(orderedEntriesBySpace: [PeerIdAndNamespace: OrderedHistoryViewEntries], holes: HistoryViewHoles, anchor: HistoryViewAnchor, tag: MessageTags?) -> (clipRanges: [ClosedRange<MessageIndex>], sampledHole: SampledHistoryViewHole?) {
|
||||||
var clipRanges: [ClosedRange<MessageIndex>] = []
|
var clipRanges: [ClosedRange<MessageIndex>] = []
|
||||||
var sampledHole: (index: MessageIndex, hole: SampledHistoryViewHole)?
|
var sampledHole: (index: MessageIndex, hole: SampledHistoryViewHole)?
|
||||||
for (space, items) in orderedEntriesBySpace {
|
|
||||||
guard let indices = holes.holesBySpace[space], !indices.isEmpty else {
|
for (space, indices) in holes.holesBySpace {
|
||||||
|
if indices.isEmpty {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch anchor {
|
switch anchor {
|
||||||
case .lowerBound, .upperBound:
|
case .lowerBound, .upperBound:
|
||||||
break
|
break
|
||||||
case let .index(index):
|
case let .index(index):
|
||||||
|
if index.id.peerId == space.peerId && index.id.namespace == space.namespace {
|
||||||
if indices.contains(Int(index.id.id)) {
|
if indices.contains(Int(index.id.id)) {
|
||||||
return ([MessageIndex.absoluteLowerBound() ... MessageIndex.absoluteUpperBound()], SampledHistoryViewHole(peerId: space.peerId, namespace: space.namespace, tag: tag, indices: indices, startId: index.id.id, endId: nil))
|
return ([MessageIndex.absoluteLowerBound() ... MessageIndex.absoluteUpperBound()], SampledHistoryViewHole(peerId: space.peerId, namespace: space.namespace, tag: tag, indices: indices, startId: index.id.id, endId: nil))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
guard let items = orderedEntriesBySpace[space] else {
|
||||||
|
return ([MessageIndex.absoluteLowerBound() ... MessageIndex.absoluteUpperBound()], SampledHistoryViewHole(peerId: space.peerId, namespace: space.namespace, tag: tag, indices: indices, startId: Int32.max - 1, endId: 1))
|
||||||
|
}
|
||||||
if items.entries.isEmpty {
|
if items.entries.isEmpty {
|
||||||
return ([MessageIndex.absoluteLowerBound() ... MessageIndex.absoluteUpperBound()], SampledHistoryViewHole(peerId: space.peerId, namespace: space.namespace, tag: tag, indices: indices, startId: Int32.max - 1, endId: 1))
|
return ([MessageIndex.absoluteLowerBound() ... MessageIndex.absoluteUpperBound()], SampledHistoryViewHole(peerId: space.peerId, namespace: space.namespace, tag: tag, indices: indices, startId: Int32.max - 1, endId: 1))
|
||||||
}
|
}
|
||||||
@ -229,8 +249,11 @@ private func sampleHoleRanges(orderedEntriesBySpace: [PeerIdAndNamespace: Ordere
|
|||||||
anchorStartingMessageId = items.entries[anchorIndex].index.id.id
|
anchorStartingMessageId = items.entries[anchorIndex].index.id.id
|
||||||
}
|
}
|
||||||
|
|
||||||
var lowerDirectionIndex = anchorIndex
|
let startingLowerDirectionIndex = anchorIndex
|
||||||
var higherDirectionIndex = anchorIndex + 1
|
let startingHigherDirectionIndex = anchorIndex + 1
|
||||||
|
|
||||||
|
var lowerDirectionIndex = startingLowerDirectionIndex
|
||||||
|
var higherDirectionIndex = startingHigherDirectionIndex
|
||||||
while lowerDirectionIndex >= 0 || higherDirectionIndex < items.entries.count {
|
while lowerDirectionIndex >= 0 || higherDirectionIndex < items.entries.count {
|
||||||
if lowerDirectionIndex >= 0 {
|
if lowerDirectionIndex >= 0 {
|
||||||
let itemIndex = items.entries[lowerDirectionIndex].index
|
let itemIndex = items.entries[lowerDirectionIndex].index
|
||||||
@ -238,17 +261,23 @@ private func sampleHoleRanges(orderedEntriesBySpace: [PeerIdAndNamespace: Ordere
|
|||||||
if lowerDirectionIndex == 0 && itemBoundaryMessageId == bounds.lower.id.id {
|
if lowerDirectionIndex == 0 && itemBoundaryMessageId == bounds.lower.id.id {
|
||||||
itemBoundaryMessageId = 1
|
itemBoundaryMessageId = 1
|
||||||
}
|
}
|
||||||
|
let previousBoundaryIndex: MessageIndex
|
||||||
|
if lowerDirectionIndex == startingLowerDirectionIndex {
|
||||||
|
previousBoundaryIndex = itemIndex
|
||||||
|
} else {
|
||||||
|
previousBoundaryIndex = items.entries[lowerDirectionIndex + 1].index
|
||||||
|
}
|
||||||
if indices.intersects(integersIn: min(Int(anchorStartingMessageId), Int(itemBoundaryMessageId)) ... max(Int(anchorStartingMessageId), Int(itemBoundaryMessageId))) {
|
if indices.intersects(integersIn: min(Int(anchorStartingMessageId), Int(itemBoundaryMessageId)) ... max(Int(anchorStartingMessageId), Int(itemBoundaryMessageId))) {
|
||||||
var itemClipIndex: MessageIndex
|
var itemClipIndex: MessageIndex
|
||||||
if indices.contains(Int(itemIndex.id.id)) {
|
if indices.contains(Int(previousBoundaryIndex.id.id)) {
|
||||||
itemClipIndex = itemIndex
|
itemClipIndex = previousBoundaryIndex
|
||||||
} else {
|
} else {
|
||||||
itemClipIndex = itemIndex.predecessor()
|
itemClipIndex = previousBoundaryIndex.predecessor()
|
||||||
}
|
}
|
||||||
clipRanges.append(MessageIndex.absoluteLowerBound() ... itemClipIndex)
|
clipRanges.append(MessageIndex.absoluteLowerBound() ... itemClipIndex)
|
||||||
var replaceHole = false
|
var replaceHole = false
|
||||||
if let (currentIndex, _) = sampledHole {
|
if let (currentIndex, _) = sampledHole {
|
||||||
if isIndex(index: itemIndex, closerTo: anchor, than: currentIndex) {
|
if isIndex(index: itemClipIndex, closerTo: anchor, than: currentIndex) {
|
||||||
replaceHole = true
|
replaceHole = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -257,12 +286,16 @@ private func sampleHoleRanges(orderedEntriesBySpace: [PeerIdAndNamespace: Ordere
|
|||||||
|
|
||||||
if replaceHole {
|
if replaceHole {
|
||||||
let holeStartId: MessageId.Id
|
let holeStartId: MessageId.Id
|
||||||
if indices.contains(Int(itemIndex.id.id)) {
|
if indices.contains(Int(previousBoundaryIndex.id.id)) {
|
||||||
holeStartId = itemIndex.id.id
|
holeStartId = previousBoundaryIndex.id.id
|
||||||
} else {
|
} else {
|
||||||
holeStartId = itemIndex.id.id - 1
|
holeStartId = previousBoundaryIndex.id.id - 1
|
||||||
|
}
|
||||||
|
if let idInHole = indices.integerLessThanOrEqualTo(IndexSet.Element(holeStartId)) {
|
||||||
|
sampledHole = (itemIndex, SampledHistoryViewHole(peerId: space.peerId, namespace: space.namespace, tag: tag, indices: indices, startId: MessageId.Id(idInHole), endId: 1))
|
||||||
|
} else {
|
||||||
|
assertionFailure()
|
||||||
}
|
}
|
||||||
sampledHole = (itemIndex, SampledHistoryViewHole(peerId: space.peerId, namespace: space.namespace, tag: tag, indices: indices, startId: holeStartId, endId: 1))
|
|
||||||
}
|
}
|
||||||
lowerDirectionIndex = -1
|
lowerDirectionIndex = -1
|
||||||
}
|
}
|
||||||
@ -299,7 +332,9 @@ private func sampleHoleRanges(orderedEntriesBySpace: [PeerIdAndNamespace: Ordere
|
|||||||
} else {
|
} else {
|
||||||
holeStartId = itemIndex.id.id + 1
|
holeStartId = itemIndex.id.id + 1
|
||||||
}
|
}
|
||||||
sampledHole = (itemIndex, SampledHistoryViewHole(peerId: space.peerId, namespace: space.namespace, tag: tag, indices: indices, startId: holeStartId, endId: Int32.max - 1))
|
if let idInHole = indices.integerGreaterThanOrEqualTo(IndexSet.Element(holeStartId)) {
|
||||||
|
sampledHole = (itemIndex, SampledHistoryViewHole(peerId: space.peerId, namespace: space.namespace, tag: tag, indices: indices, startId: MessageId.Id(idInHole), endId: Int32.max - 1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
higherDirectionIndex = items.entries.count
|
higherDirectionIndex = items.entries.count
|
||||||
}
|
}
|
||||||
@ -313,15 +348,31 @@ private func sampleHoleRanges(orderedEntriesBySpace: [PeerIdAndNamespace: Ordere
|
|||||||
struct HistoryViewHoles {
|
struct HistoryViewHoles {
|
||||||
var holesBySpace: [PeerIdAndNamespace: IndexSet]
|
var holesBySpace: [PeerIdAndNamespace: IndexSet]
|
||||||
|
|
||||||
mutating func insertHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) {
|
mutating func insertHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) -> Bool {
|
||||||
if self.holesBySpace[space] == nil {
|
if self.holesBySpace[space] == nil {
|
||||||
self.holesBySpace[space] = IndexSet()
|
self.holesBySpace[space] = IndexSet()
|
||||||
}
|
}
|
||||||
self.holesBySpace[space]!.insert(integersIn: Int(range.lowerBound) ... Int(range.upperBound))
|
let intRange = Int(range.lowerBound) ... Int(range.upperBound)
|
||||||
|
if self.holesBySpace[space]!.contains(integersIn: intRange) {
|
||||||
|
self.holesBySpace[space]!.insert(integersIn: intRange)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func removeHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) {
|
mutating func removeHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) -> Bool {
|
||||||
self.holesBySpace[space]?.remove(integersIn: Int(range.lowerBound) ... Int(range.upperBound))
|
if self.holesBySpace[space] != nil {
|
||||||
|
let intRange = Int(range.lowerBound) ... Int(range.upperBound)
|
||||||
|
if self.holesBySpace[space]!.intersects(integersIn: intRange) {
|
||||||
|
self.holesBySpace[space]!.remove(integersIn: intRange)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,6 +382,7 @@ struct OrderedHistoryViewEntries {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct HistoryViewLoadedSample {
|
struct HistoryViewLoadedSample {
|
||||||
|
let anchor: HistoryViewAnchor
|
||||||
let entries: [MessageHistoryMessageEntry]
|
let entries: [MessageHistoryMessageEntry]
|
||||||
let holesToLower: Bool
|
let holesToLower: Bool
|
||||||
let holesToHigher: Bool
|
let holesToHigher: Bool
|
||||||
@ -382,7 +434,7 @@ final class HistoryViewLoadedState {
|
|||||||
let upperBound = MessageIndex.upperBound(peerId: space.peerId, namespace: space.namespace)
|
let upperBound = MessageIndex.upperBound(peerId: space.peerId, namespace: space.namespace)
|
||||||
switch self.anchor {
|
switch self.anchor {
|
||||||
case let .index(index):
|
case let .index(index):
|
||||||
anchorIndex = index
|
anchorIndex = index.withPeerId(space.peerId).withNamespace(space.namespace)
|
||||||
case .lowerBound:
|
case .lowerBound:
|
||||||
anchorIndex = lowerBound
|
anchorIndex = lowerBound
|
||||||
case .upperBound:
|
case .upperBound:
|
||||||
@ -441,12 +493,12 @@ final class HistoryViewLoadedState {
|
|||||||
self.orderedEntriesBySpace[space] = OrderedHistoryViewEntries(entries: messages, bounds: bounds)
|
self.orderedEntriesBySpace[space] = OrderedHistoryViewEntries(entries: messages, bounds: bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) {
|
func insertHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) -> Bool {
|
||||||
self.holes.insertHole(space: space, range: range)
|
return self.holes.insertHole(space: space, range: range)
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) {
|
func removeHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) -> Bool {
|
||||||
self.holes.removeHole(space: space, range: range)
|
return self.holes.removeHole(space: space, range: range)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateTimestamp(postbox: Postbox, index: MessageIndex, timestamp: Int32) -> Bool {
|
func updateTimestamp(postbox: Postbox, index: MessageIndex, timestamp: Int32) -> Bool {
|
||||||
@ -648,7 +700,9 @@ final class HistoryViewLoadedState {
|
|||||||
result.append(entry)
|
result.append(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return HistoryViewLoadedSample(entries: result, holesToLower: holesToLower, holesToHigher: holesToHigher, hole: sampledHole)
|
let stableIds = Set(result.map({ $0.message.stableId }))
|
||||||
|
assert(stableIds.count == result.count)
|
||||||
|
return HistoryViewLoadedSample(anchor: self.anchor, entries: result, holesToLower: holesToLower, holesToHigher: holesToHigher, hole: sampledHole)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,12 +748,12 @@ final class HistoryViewLoadingState {
|
|||||||
self.holes = HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag))
|
self.holes = HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) {
|
func insertHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) -> Bool {
|
||||||
self.holes.insertHole(space: space, range: range)
|
return self.holes.insertHole(space: space, range: range)
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) {
|
func removeHole(space: PeerIdAndNamespace, range: ClosedRange<MessageId.Id>) -> Bool {
|
||||||
self.holes.removeHole(space: space, range: range)
|
return self.holes.removeHole(space: space, range: range)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkAndSample(postbox: Postbox) -> HistoryViewLoadingSample {
|
func checkAndSample(postbox: Postbox) -> HistoryViewLoadingSample {
|
||||||
|
@ -624,9 +624,9 @@ public final class Transaction {
|
|||||||
return self.postbox?.messageHistoryTable.findMessageId(peerId: peerId, namespace: namespace, timestamp: timestamp)
|
return self.postbox?.messageHistoryTable.findMessageId(peerId: peerId, namespace: namespace, timestamp: timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func findClosestMessageIdByTimestamp(peerId: PeerId, namespace: MessageId.Namespace, timestamp: Int32) -> MessageId? {
|
public func findClosestMessageIdByTimestamp(peerId: PeerId, timestamp: Int32) -> MessageId? {
|
||||||
assert(!self.disposed)
|
assert(!self.disposed)
|
||||||
return self.postbox?.messageHistoryTable.findClosestMessageId(peerId: peerId, namespace: namespace, timestamp: timestamp)
|
return self.postbox?.messageHistoryTable.findClosestMessageIndex(peerId: peerId, timestamp: timestamp)?.id
|
||||||
}
|
}
|
||||||
|
|
||||||
public func findRandomMessage(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags, ignoreIds: ([MessageId], Set<MessageId>)) -> MessageIndex? {
|
public func findRandomMessage(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags, ignoreIds: ([MessageId], Set<MessageId>)) -> MessageIndex? {
|
||||||
@ -992,7 +992,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
|
|||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
//debugSaveState(basePath: basePath, name: "previous1")
|
//debugSaveState(basePath: basePath, name: "previous1")
|
||||||
//debugRestoreState(basePath: basePath, name: "previous1")
|
debugRestoreState(basePath: basePath, name: "previous1")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
let startTime = CFAbsoluteTimeGetCurrent()
|
let startTime = CFAbsoluteTimeGetCurrent()
|
||||||
@ -2229,7 +2229,7 @@ public final class Postbox {
|
|||||||
subscriber.putCompletion()
|
subscriber.putCompletion()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if self.queue.isCurrent() {
|
if self.queue.isCurrent() && Queue.mainQueue().isCurrent() {
|
||||||
f()
|
f()
|
||||||
} else if userInteractive {
|
} else if userInteractive {
|
||||||
self.queue.justDispatchWithQoS(qos: DispatchQoS.userInteractive, f)
|
self.queue.justDispatchWithQoS(qos: DispatchQoS.userInteractive, f)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user