Swiftgram/Postbox/ChatListTable.swift
2016-02-01 03:06:14 +03:00

157 lines
6.3 KiB
Swift

import Foundation
enum ChatListOperation {
case InsertMessage(IntermediateMessage)
case InsertNothing(MessageIndex)
case Remove([MessageIndex])
}
enum ChatListIntermediateEntry {
case Message(IntermediateMessage)
case Nothing(MessageIndex)
}
final class ChatListTable {
let valueBox: ValueBox
let tableId: Int32
let indexTable: ChatListIndexTable
init(valueBox: ValueBox, tableId: Int32, indexTable: ChatListIndexTable) {
self.valueBox = valueBox
self.tableId = tableId
self.indexTable = indexTable
}
private func key(index: MessageIndex) -> ValueBoxKey {
let key = ValueBoxKey(length: 4 + 4 + 4 + 8)
key.setInt32(0, value: index.timestamp)
key.setInt32(4, value: index.id.namespace)
key.setInt32(4 + 4, value: index.id.id)
key.setInt64(4 + 4 + 4, value: index.id.peerId.toInt64())
return key
}
private func lowerBound() -> ValueBoxKey {
let key = ValueBoxKey(length: 4)
key.setInt32(0, value: 0)
return key
}
private func upperBound() -> ValueBoxKey {
let key = ValueBoxKey(length: 4)
key.setInt32(0, value: Int32.max)
return key
}
func replay(historyOperationsByPeerId: [PeerId : [MessageHistoryOperation]], messageHistoryTable: MessageHistoryTable, inout operations: [ChatListOperation]) {
for (peerId, _) in historyOperationsByPeerId {
let currentIndex: MessageIndex? = self.indexTable.get(peerId)
if let topMessage = messageHistoryTable.topMessage(peerId) {
let index = MessageIndex(id: topMessage.id, timestamp: topMessage.timestamp)
if let currentIndex = currentIndex where currentIndex != index {
self.justRemove(currentIndex)
}
if let currentIndex = currentIndex {
operations.append(.Remove([currentIndex]))
}
self.indexTable.set(index)
self.justInsert(index)
operations.append(.InsertMessage(topMessage))
} else {
if let currentIndex = currentIndex {
operations.append(.Remove([currentIndex]))
operations.append(.InsertNothing(currentIndex))
}
}
}
}
func justInsert(index: MessageIndex) {
self.valueBox.set(self.tableId, key: self.key(index), value: MemoryBuffer(memory: nil, capacity: 0, length: 0, freeWhenDone: false))
}
func justRemove(index: MessageIndex) {
self.valueBox.remove(self.tableId, key: self.key(index))
}
func entriesAround(index: MessageIndex, messageHistoryTable: MessageHistoryTable, count: Int) -> [ChatListIntermediateEntry] {
var lowerEntries: [ChatListIntermediateEntry] = []
self.valueBox.range(self.tableId, start: self.key(index).successor, end: self.lowerBound(), keys: { key in
let index = MessageIndex(id: MessageId(peerId: PeerId(key.getInt64(4 + 4 + 4)), namespace: key.getInt32(4), id: key.getInt32(4 + 4)), timestamp: key.getInt32(0))
if let message = messageHistoryTable.getMessage(index) {
lowerEntries.append(.Message(message))
} else {
lowerEntries.append(.Nothing(index))
}
return true
}, limit: count)
var upperEntries: [ChatListIntermediateEntry] = []
self.valueBox.range(self.tableId, start: self.key(index), end: self.upperBound(), keys: { key in
let index = MessageIndex(id: MessageId(peerId: PeerId(key.getInt64(4 + 4 + 4)), namespace: key.getInt32(4), id: key.getInt32(4 + 4)), timestamp: key.getInt32(0))
if let message = messageHistoryTable.getMessage(index) {
upperEntries.append(.Message(message))
} else {
upperEntries.append(.Nothing(index))
}
return true
}, limit: count)
var entries: [ChatListIntermediateEntry] = []
for entry in lowerEntries.reverse() {
entries.append(entry)
}
entries.appendContentsOf(upperEntries)
return entries
}
func earlierEntries(index: MessageIndex?, messageHistoryTable: MessageHistoryTable, count: Int) -> [ChatListIntermediateEntry] {
var entries: [ChatListIntermediateEntry] = []
let key: ValueBoxKey
if let index = index {
key = self.key(index)
} else {
key = self.upperBound()
}
self.valueBox.range(self.tableId, start: key, end: self.lowerBound(), keys: { key in
let index = MessageIndex(id: MessageId(peerId: PeerId(key.getInt64(4 + 4 + 4)), namespace: key.getInt32(4), id: key.getInt32(4 + 4)), timestamp: key.getInt32(0))
if let message = messageHistoryTable.getMessage(index) {
entries.append(.Message(message))
} else {
entries.append(.Nothing(index))
}
return true
}, limit: count)
return entries
}
func laterEntries(index: MessageIndex?, messageHistoryTable: MessageHistoryTable, count: Int) -> [ChatListIntermediateEntry] {
var entries: [ChatListIntermediateEntry] = []
let key: ValueBoxKey
if let index = index {
key = self.key(index)
} else {
key = self.lowerBound()
}
self.valueBox.range(self.tableId, start: key, end: self.upperBound(), keys: { key in
let index = MessageIndex(id: MessageId(peerId: PeerId(key.getInt64(4 + 4 + 4)), namespace: key.getInt32(4), id: key.getInt32(4 + 4)), timestamp: key.getInt32(0))
if let message = messageHistoryTable.getMessage(index) {
entries.append(.Message(message))
} else {
entries.append(.Nothing(index))
}
return true
}, limit: count)
return entries
}
func debugList(messageHistoryTable: MessageHistoryTable) -> [ChatListIntermediateEntry] {
return self.entriesAround(MessageIndex(id: MessageId(peerId: PeerId(0), namespace: 0, id: 0), timestamp: 0), messageHistoryTable: messageHistoryTable, count: 1000)
}
}