Swiftgram/submodules/Postbox/Sources/PendingMessageActionsTable.swift
2021-09-13 20:40:09 +04:00

182 lines
8.0 KiB
Swift

import Foundation
public protocol PendingMessageActionData: PostboxCoding {
func isEqual(to: PendingMessageActionData) -> Bool
}
public struct PendingMessageActionsEntry {
public let id: MessageId
public let action: PendingMessageActionData
public init(id: MessageId, action: PendingMessageActionData) {
self.id = id
self.action = action
}
}
public struct PendingMessageActionType: RawRepresentable, Equatable, Hashable {
public var rawValue: UInt32
public init(rawValue: UInt32) {
self.rawValue = rawValue
}
}
enum PendingMessageActionsOperation {
case add(PendingMessageActionType, MessageId, PendingMessageActionData)
case remove(PendingMessageActionType, MessageId)
}
struct PendingMessageActionsSummaryKey: Equatable, Hashable {
let type: PendingMessageActionType
let peerId: PeerId
let namespace: MessageId.Namespace
}
private func getReverseId(_ key: ValueBoxKey) -> MessageId {
return MessageId(peerId: PeerId(key.getInt64(1 + 4)), namespace: key.getInt32(1 + 4 + 8), id: key.getInt32(1 + 4 + 8 + 4))
}
private func getActionType(_ key: ValueBoxKey) -> PendingMessageActionType {
return PendingMessageActionType(rawValue: key.getUInt32(1 + 8 + 4 + 4))
}
private enum PendingMessageActionsTableSection: UInt8 {
case actions = 0
case index = 1
}
final class PendingMessageActionsTable: Table {
static func tableSpec(_ id: Int32) -> ValueBoxTable {
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: true)
}
private let metadataTable: PendingMessageActionsMetadataTable
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, metadataTable: PendingMessageActionsMetadataTable) {
self.metadataTable = metadataTable
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func forwardKey(id: MessageId, actionType: PendingMessageActionType) -> ValueBoxKey {
let key = ValueBoxKey(length: 1 + 8 + 4 + 4 + 4)
key.setUInt8(0, value: PendingMessageActionsTableSection.actions.rawValue)
key.setInt64(1, value: id.peerId.toInt64())
key.setInt32(1 + 8, value: id.namespace)
key.setInt32(1 + 8 + 4, value: id.id)
key.setUInt32(1 + 8 + 4 + 4, value: actionType.rawValue)
return key
}
private func reverseKey(id: MessageId, actionType: PendingMessageActionType) -> ValueBoxKey {
let key = ValueBoxKey(length: 1 + 8 + 4 + 4 + 4)
key.setUInt8(0, value: PendingMessageActionsTableSection.index.rawValue)
key.setUInt32(1, value: actionType.rawValue)
key.setInt64(1 + 4, value: id.peerId.toInt64())
key.setInt32(1 + 4 + 8, value: id.namespace)
key.setInt32(1 + 4 + 8 + 4, value: id.id)
return key
}
private func lowerBoundForward(id: MessageId) -> ValueBoxKey {
let key = ValueBoxKey(length: 1 + 8 + 4 + 4)
key.setUInt8(0, value: PendingMessageActionsTableSection.actions.rawValue)
key.setInt64(1, value: id.peerId.toInt64())
key.setInt32(1 + 8, value: id.namespace)
key.setInt32(1 + 8 + 4, value: id.id)
return key
}
private func upperBoundForward(id: MessageId) -> ValueBoxKey {
return self.lowerBoundForward(id: id).successor
}
private func lowerBoundReverse(type: PendingMessageActionType) -> ValueBoxKey {
let key = ValueBoxKey(length: 1 + 4)
key.setUInt8(0, value: PendingMessageActionsTableSection.index.rawValue)
key.setUInt32(1, value: type.rawValue)
return key
}
private func upperBoundReverse(type: PendingMessageActionType) -> ValueBoxKey {
return self.lowerBoundReverse(type: type).successor
}
func getAction(id: MessageId, type: PendingMessageActionType) -> PendingMessageActionData? {
if let value = self.valueBox.get(self.table, key: self.forwardKey(id: id, actionType: type)) {
if let action = PostboxDecoder(buffer: value).decodeRootObject() as? PendingMessageActionData {
return action
} else {
assertionFailure()
return nil
}
} else {
return nil
}
}
func setAction(id: MessageId, type: PendingMessageActionType, action: PendingMessageActionData?, operations: inout [PendingMessageActionsOperation], updatedSummaries: inout [PendingMessageActionsSummaryKey: Int32]) {
let currentAction = self.getAction(id: id, type: type)
if let action = action {
let encoder = PostboxEncoder()
encoder.encodeRootObject(action)
self.valueBox.set(self.table, key: self.forwardKey(id: id, actionType: type), value: encoder.readBufferNoCopy())
self.valueBox.set(self.table, key: self.reverseKey(id: id, actionType: type), value: MemoryBuffer())
if currentAction != nil {
operations.append(.remove(type, id))
}
operations.append(.add(type, id, action))
if currentAction == nil {
let updatedCount = self.metadataTable.addCount(.peerNamespaceAction(id.peerId, id.namespace, type), value: 1)
updatedSummaries[PendingMessageActionsSummaryKey(type: type, peerId: id.peerId, namespace: id.namespace)] = updatedCount
let _ = self.metadataTable.addCount(.peerNamespace(id.peerId, id.namespace), value: 1)
}
} else if currentAction != nil {
operations.append(.remove(type, id))
self.valueBox.remove(self.table, key: self.forwardKey(id: id, actionType: type), secure: false)
self.valueBox.remove(self.table, key: self.reverseKey(id: id, actionType: type), secure: false)
let updatedCount = self.metadataTable.addCount(.peerNamespaceAction(id.peerId, id.namespace, type), value: -1)
updatedSummaries[PendingMessageActionsSummaryKey(type: type, peerId: id.peerId, namespace: id.namespace)] = updatedCount
let _ = self.metadataTable.addCount(.peerNamespace(id.peerId, id.namespace), value: -1)
}
}
func removeMessage(id: MessageId, operations: inout [PendingMessageActionsOperation], updatedSummaries: inout [PendingMessageActionsSummaryKey: Int32]) {
if self.metadataTable.getCount(.peerNamespace(id.peerId, id.namespace)) != 0 {
var removeTypes: [PendingMessageActionType] = []
self.valueBox.range(self.table, start: self.lowerBoundForward(id: id), end: self.upperBoundForward(id: id), keys: { key in
removeTypes.append(getActionType(key))
return true
}, limit: 0)
for type in removeTypes {
operations.append(.remove(type, id))
self.valueBox.remove(self.table, key: self.forwardKey(id: id, actionType: type), secure: false)
self.valueBox.remove(self.table, key: self.reverseKey(id: id, actionType: type), secure: false)
let updatedCount = self.metadataTable.addCount(.peerNamespaceAction(id.peerId, id.namespace, type), value: -1)
updatedSummaries[PendingMessageActionsSummaryKey(type: type, peerId: id.peerId, namespace: id.namespace)] = updatedCount
}
let _ = self.metadataTable.addCount(.peerNamespace(id.peerId, id.namespace), value: Int32(-removeTypes.count))
}
}
func getActions(type: PendingMessageActionType) -> [PendingMessageActionsEntry] {
var ids: [MessageId] = []
self.valueBox.range(self.table, start: self.lowerBoundReverse(type: type), end: self.upperBoundReverse(type: type), keys: { key in
ids.append(getReverseId(key))
return true
}, limit: 0)
var entries: [PendingMessageActionsEntry] = []
for id in ids {
if let action = self.getAction(id: id, type: type) {
entries.append(PendingMessageActionsEntry(id: id, action: action))
} else {
assertionFailure()
}
}
return entries
}
}