ChatListIndexTable
enum
PeerChatListInclusion
1
2
case notIncluded
case ifHasMessagesOrOneOf(groupId: PeerGroupId, pinningIndex: UInt16?, minTimestamp: Int32?)
struct
ChatListPeerInclusionIndex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
let topMessageIndex: MessageIndex?
let inclusion: PeerChatListInclusion
func includedIndex(peerId: PeerId) -> (PeerGroupId, ChatListIndex)? {
switch inclusion {
case .notIncluded:
return nil
case let .ifHasMessagesOrOneOf(groupId, pinningIndex, minTimestamp):
if let minTimestamp = minTimestamp {
if let topMessageIndex = self.topMessageIndex, topMessageIndex.timestamp >= minTimestamp {
return (groupId, ChatListIndex(pinningIndex: pinningIndex, messageIndex: topMessageIndex))
} else {
return (groupId, ChatListIndex(pinningIndex: pinningIndex, messageIndex: MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 0), timestamp: minTimestamp)))
}
} else if let topMessageIndex = self.topMessageIndex {
return (groupId, ChatListIndex(pinningIndex: pinningIndex, messageIndex: topMessageIndex))
} else if let pinningIndex = pinningIndex {
return (groupId, ChatListIndex(pinningIndex: pinningIndex, messageIndex: MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 0), timestamp: 0)))
} else {
return nil
}
}
}
struct
ChatListIndexFlags
1
2
var rawValue: Int8
static let hasIndex = ChatListIndexFlags(rawValue: 1 << 0)
class
ChatListIndexTable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
static func tableSpec(_ id: Int32) -> ValueBoxTable {
return ValueBoxTable(id: id, keyType: .int64, compactValuesOnCreation: true)
}
private let peerNameIndexTable: PeerNameIndexTable
private let metadataTable: MessageHistoryMetadataTable
private let readStateTable: MessageHistoryReadStateTable
private let notificationSettingsTable: PeerNotificationSettingsTable
private var cachedPeerIndices: [PeerId: ChatListPeerInclusionIndex] = [:]
private var updatedPreviousPeerCachedIndices: [PeerId: ChatListPeerInclusionIndex] = [:]
private func key(_ peerId: PeerId) -> ValueBoxKey {
// peerId
self.sharedKey.setInt64(0, value: peerId.toInt64())
assert(self.sharedKey.getInt64(0) == peerId.toInt64())
return self.sharedKey
}
private func key(_ groupId: PeerGroupId) -> ValueBoxKey {
// 0xFFFFFF groupId
self.sharedKey.setInt32(0, value: Int32.max)
self.sharedKey.setInt32(4, value: groupId.rawValue)
return self.sharedKey
}
// update topMessageIndex
func setTopMessageIndex(peerId: PeerId, index: MessageIndex?) -> ChatListPeerInclusionIndex {
let current = self.get(peerId: peerId)
if self.updatedPreviousPeerCachedIndices[peerId] == nil {
self.updatedPreviousPeerCachedIndices[peerId] = current
}
let updated = ChatListPeerInclusionIndex(topMessageIndex: index, inclusion: current.inclusion)
self.cachedPeerIndices[peerId] = updated
return updated
}
// update inclusion
func setInclusion(peerId: PeerId, inclusion: PeerChatListInclusion) -> ChatListPeerInclusionIndex {
let current = self.get(peerId: peerId)
if self.updatedPreviousPeerCachedIndices[peerId] == nil {
self.updatedPreviousPeerCachedIndices[peerId] = current
}
let updated = ChatListPeerInclusionIndex(topMessageIndex: current.topMessageIndex, inclusion: inclusion)
self.cachedPeerIndices[peerId] = updated
return updated
}
// get
func get(peerId: PeerId) -> ChatListPeerInclusionIndex {
if let cached = self.cachedPeerIndices[peerId] {// read from cache
return cached
} else {
// read from disk
if let value = self.valueBox.get(self.table, key: self.key(peerId)) {
let topMessageIndex: MessageIndex?
// read indexFlags
var flagsValue: Int8 = 0
value.read(&flagsValue, offset: 0, length: 1)
let flags = ChatListIndexFlags(rawValue: flagsValue)
if flags.contains(.hasIndex) {
var idNamespace: Int32 = 0
var idId: Int32 = 0
var idTimestamp: Int32 = 0
value.read(&idNamespace, offset: 0, length: 4)
value.read(&idId, offset: 0, length: 4)
value.read(&idTimestamp, offset: 0, length: 4)
topMessageIndex = MessageIndex(id: MessageId(peerId: peerId, namespace: idNamespace, id: idId), timestamp: idTimestamp)
} else {
topMessageIndex = nil
}
// read inclusion
let inclusion: PeerChatListInclusion
var inclusionId: Int8 = 0
value.read(&inclusionId, offset: 0, length: 1)
if inclusionId == 0 {
inclusion = .notIncluded
} else if inclusionId == 1 {
// read pinning index
var pinningIndexValue: UInt16 = 0
value.read(&pinningIndexValue, offset: 0, length: 2)
// read hasMinTimestamp
var hasMinTimestamp: Int8 = 0
value.read(&hasMinTimestamp, offset: 0, length: 1)
let minTimestamp: Int32?
if hasMinTimestamp != 0 {
var minTimestampValue: Int32 = 0
// read minTimestampValue
value.read(&minTimestampValue, offset: 0, length: 4)
minTimestamp = minTimestampValue
} else {
minTimestamp = nil
}
// read groupId
var groupIdValue: Int32 = 0
value.read(&groupIdValue, offset: 0, length: 4)
inclusion = .ifHasMessagesOrOneOf(groupId: PeerGroupId(rawValue: groupIdValue), pinningIndex: chatListPinningIndexFromKeyValue(pinningIndexValue), minTimestamp: minTimestamp)
} else {
preconditionFailure()
}
let inclusionIndex = ChatListPeerInclusionIndex(topMessageIndex: topMessageIndex, inclusion: inclusion)
self.cachedPeerIndices[peerId] = inclusionIndex
return inclusionIndex
} else {
// (nil, included)
let inclusionIndex = ChatListPeerInclusionIndex(topMessageIndex: nil, inclusion: .notIncluded)
self.cachedPeerIndices[peerId] = inclusionIndex
return inclusionIndex
}
}
}