Update notification service

This commit is contained in:
Ali 2021-09-13 20:40:09 +04:00
parent e4d277daf9
commit 0553a14eb3
50 changed files with 600 additions and 796 deletions

View File

@ -15,7 +15,8 @@ swift_library(
"//submodules/EncryptionProvider:EncryptionProvider",
"//submodules/AppLockState:AppLockState",
"//submodules/NotificationsPresentationData:NotificationsPresentationData",
"//Telegram/NotificationService/NotificationServiceObjC:NotificationServiceObjC",
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider"
],
visibility = [
"//visibility:public",

View File

@ -1,17 +0,0 @@
import Foundation
/*import ValueBox
private func applicationSpecificSharedDataKey(_ value: Int32) -> ValueBoxKey {
let key = ValueBoxKey(length: 4)
key.setInt32(0, value: value + 1000)
return key
}
private enum ApplicationSpecificSharedDataKeyValues: Int32 {
case inAppNotificationSettings = 0
}
public struct ApplicationSpecificSharedDataKeys {
public static let inAppNotificationSettings = applicationSpecificSharedDataKey(ApplicationSpecificSharedDataKeyValues.inAppNotificationSettings.rawValue)
}
*/

View File

@ -1 +0,0 @@
import Foundation

View File

@ -1,55 +0,0 @@
/*import PostboxDataTypes
struct LegacyPeerSummaryCounterTags: OptionSet, Sequence, Hashable {
var rawValue: Int32
init(rawValue: Int32) {
self.rawValue = rawValue
}
static let regularChatsAndPrivateGroups = LegacyPeerSummaryCounterTags(rawValue: 1 << 0)
static let publicGroups = LegacyPeerSummaryCounterTags(rawValue: 1 << 1)
static let channels = LegacyPeerSummaryCounterTags(rawValue: 1 << 2)
public func makeIterator() -> AnyIterator<LegacyPeerSummaryCounterTags> {
var index = 0
return AnyIterator { () -> LegacyPeerSummaryCounterTags? in
while index < 31 {
let currentTags = self.rawValue >> UInt32(index)
let tag = LegacyPeerSummaryCounterTags(rawValue: 1 << UInt32(index))
index += 1
if currentTags == 0 {
break
}
if (currentTags & 1) != 0 {
return tag
}
}
return nil
}
}
}
extension PeerSummaryCounterTags {
static let privateChat = PeerSummaryCounterTags(rawValue: 1 << 3)
static let secretChat = PeerSummaryCounterTags(rawValue: 1 << 4)
static let privateGroup = PeerSummaryCounterTags(rawValue: 1 << 5)
static let bot = PeerSummaryCounterTags(rawValue: 1 << 6)
static let channel = PeerSummaryCounterTags(rawValue: 1 << 7)
static let publicGroup = PeerSummaryCounterTags(rawValue: 1 << 8)
}
struct Namespaces {
struct Message {
static let Cloud: Int32 = 0
}
struct Peer {
static let CloudUser: Int32 = 0
static let CloudGroup: Int32 = 1
static let CloudChannel: Int32 = 2
static let SecretChat: Int32 = 3
}
}
*/

View File

@ -1,53 +1,270 @@
import Foundation
import UserNotifications
import SwiftSignalKit
import NotificationServiceObjC
import Postbox
import TelegramCore
import BuildConfig
import OpenSSLEncryptionProvider
import TelegramUIPreferences
private let queue = Queue()
private var installedSharedLogger = false
private func setupSharedLogger(rootPath: String, path: String) {
if !installedSharedLogger {
installedSharedLogger = true
Logger.setSharedLogger(Logger(rootPath: rootPath, basePath: path))
}
}
private let accountAuxiliaryMethods = AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
return nil
}, fetchResourceMediaReferenceHash: { resource in
return .single(nil)
}, prepareSecretThumbnailData: { _ in
return nil
})
private func rootPathForBasePath(_ appGroupPath: String) -> String {
return appGroupPath + "/telegram-data"
}
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
private struct NotificationContent {
var title: String?
var subtitle: String?
var body: String?
var badge: Int?
func asNotificationContent() -> UNNotificationContent {
let content = UNMutableNotificationContent()
content.title = self.title ?? ""
content.subtitle = self.subtitle ?? ""
content.body = self.body ?? ""
if let badge = self.badge {
content.badge = badge as NSNumber
}
return content
}
}
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
private final class NotificationServiceHandler {
private let queue: Queue
private let accountManager: AccountManager<TelegramAccountManagerTypes>
private let encryptionParameters: ValueBoxEncryptionParameters
private var stateManager: AccountStateManager?
private let notificationKeyDisposable = MetaDisposable()
private let pollDisposable = MetaDisposable()
init?(queue: Queue, updateCurrentContent: @escaping (UNNotificationContent) -> Void, completed: @escaping () -> Void, payload: [AnyHashable: Any]) {
self.queue = queue
guard let appBundleIdentifier = Bundle.main.bundleIdentifier, let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
return nil
}
let baseAppBundleId = String(appBundleIdentifier[..<lastDotRange.lowerBound])
let buildConfig = BuildConfig(baseAppBundleId: baseAppBundleId)
let apiId: Int32 = buildConfig.apiId
let apiHash: String = buildConfig.apiHash
let languagesCategory = "ios"
let appGroupName = "group.\(baseAppBundleId)"
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
guard let appGroupUrl = maybeAppGroupUrl else {
return nil
}
let rootPath = rootPathForBasePath(appGroupUrl.path)
TempBox.initializeShared(basePath: rootPath, processType: "notification", launchSpecificId: Int64.random(in: Int64.min ... Int64.max))
let logsPath = rootPath + "/notification-logs"
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
setupSharedLogger(rootPath: rootPath, path: logsPath)
initializeAccountManagement()
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
self.accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false, useCaches: false)
let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId)
self.encryptionParameters = ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: deviceSpecificEncryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: deviceSpecificEncryptionParameters.salt)!)
let networkArguments = NetworkInitializationArguments(apiId: apiId, apiHash: apiHash, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0, voipVersions: [], appData: .single(buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), autolockDeadine: .single(nil), encryptionProvider: OpenSSLEncryptionProvider())
guard var encryptedPayload = payload["p"] as? String else {
return nil
}
encryptedPayload = encryptedPayload.replacingOccurrences(of: "-", with: "+")
encryptedPayload = encryptedPayload.replacingOccurrences(of: "_", with: "/")
while encryptedPayload.count % 4 != 0 {
encryptedPayload.append("=")
}
guard let payloadData = Data(base64Encoded: encryptedPayload) else {
return nil
}
let _ = (self.accountManager.currentAccountRecord(allocateIfNotExists: false)
|> take(1)
|> deliverOn(self.queue)).start(next: { [weak self] records in
guard let strongSelf = self, let record = records else {
return
}
let _ = (standaloneStateManager(
accountManager: strongSelf.accountManager,
networkArguments: networkArguments,
id: record.0,
encryptionParameters: strongSelf.encryptionParameters,
rootPath: rootPath,
auxiliaryMethods: accountAuxiliaryMethods
)
|> deliverOn(strongSelf.queue)).start(next: { stateManager in
guard let strongSelf = self else {
return
}
guard let stateManager = stateManager else {
completed()
return
}
strongSelf.stateManager = stateManager
strongSelf.notificationKeyDisposable.set((existingMasterNotificationsKey(postbox: stateManager.postbox)
|> deliverOn(strongSelf.queue)).start(next: { notificationsKey in
guard let strongSelf = self else {
return
}
guard let notificationsKey = notificationsKey else {
completed()
return
}
guard let decryptedPayload = decryptedNotificationPayload(key: notificationsKey, data: payloadData) else {
completed()
return
}
guard let payloadJson = try? JSONSerialization.jsonObject(with: decryptedPayload, options: []) as? [String: Any] else {
completed()
return
}
guard let aps = payloadJson["aps"] as? [String: Any] else {
completed()
return
}
var content: NotificationContent = NotificationContent()
if let alert = aps["alert"] as? [String: Any] {
content.title = alert["title"] as? String
content.subtitle = alert["subtitle"] as? String
content.body = alert["body"] as? String
} else if let alert = aps["alert"] as? String {
content.body = alert
} else {
completed()
return
}
updateCurrentContent(content.asNotificationContent())
if let stateManager = strongSelf.stateManager {
stateManager.network.shouldKeepConnection.set(.single(true))
strongSelf.pollDisposable.set(stateManager.pollStateUpdateCompletion().start(completed: {
queue.async {
guard let strongSelf = self, let stateManager = strongSelf.stateManager else {
completed()
return
}
let _ = (renderedTotalUnreadCount(
accountManager: strongSelf.accountManager,
postbox: stateManager.postbox
)
|> deliverOn(strongSelf.queue)).start(next: { value in
content.badge = Int(value.0)
updateCurrentContent(content.asNotificationContent())
completed()
})
}
}))
stateManager.reset()
} else {
completed()
}
}))
})
})
}
deinit {
self.pollDisposable.dispose()
self.stateManager?.network.shouldKeepConnection.set(.single(false))
}
}
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
private final class BoxedNotificationServiceHandler {
let value: NotificationServiceHandler?
init(value: NotificationServiceHandler?) {
self.value = value
}
}
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
@objc(NotificationService)
final class NotificationService: UNNotificationServiceExtension {
private let impl: QueueLocalObject<NotificationServiceImpl>
private var impl: QueueLocalObject<BoxedNotificationServiceHandler>?
private let content = Atomic<UNNotificationContent?>(value: nil)
private var contentHandler: ((UNNotificationContent) -> Void)?
override init() {
self.impl = QueueLocalObject(queue: queue, generate: {
var completion: ((Int32) -> Void)?
let impl = NotificationServiceImpl(serialDispatch: { f in
queue.async {
f()
}
}, countIncomingMessage: { rootPath, accountId, encryptionParameters, peerId, messageId in
completion?(0)
}, isLocked: { rootPath in
return SyncProviderImpl.isLocked(withRootPath: rootPath)
}, lockedMessageText: { rootPath in
return SyncProviderImpl.lockedMessageText(withRootPath: rootPath)
})
completion = { [weak impl] count in
queue.async {
impl?.updateUnreadCount(count)
}
}
return impl
})
super.init()
}
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.impl.with { impl in
impl.didReceive(request, withContentHandler: contentHandler)
}
let _ = self.content.swap(request.content)
self.contentHandler = contentHandler
self.impl = nil
let content = self.content
self.impl = QueueLocalObject(queue: queue, generate: { [weak self] in
return BoxedNotificationServiceHandler(value: NotificationServiceHandler(
queue: queue,
updateCurrentContent: { value in
let _ = content.swap(value)
},
completed: {
guard let strongSelf = self else {
return
}
strongSelf.impl = nil
if let content = content.with({ $0 }), let contentHandler = strongSelf.contentHandler {
contentHandler(content)
}
},
payload: request.content.userInfo
))
})
}
override func serviceExtensionTimeWillExpire() {
self.impl.with { impl in
impl.serviceExtensionTimeWillExpire()
if let content = self.content.with({ $0 }), let contentHandler = self.contentHandler {
contentHandler(content)
}
}
}

View File

@ -1,148 +0,0 @@
import Foundation
import SwiftSignalKit
//import ValueBox
//import PostboxDataTypes
//import MessageHistoryReadStateTable
//import MessageHistoryMetadataTable
//import PreferencesTable
//import PeerTable
//import PostboxCoding
import AppLockState
import NotificationsPresentationData
import BuildConfig
/*private let registeredTypes: Void = {
declareEncodable(InAppNotificationSettings.self, f: InAppNotificationSettings.init(decoder:))
declareEncodable(TelegramChannel.self, f: TelegramChannel.init(decoder:))
}()*/
private func accountRecordIdPathName(_ id: Int64) -> String {
return "account-\(UInt64(bitPattern: id))"
}
/*private final class ValueBoxLoggerImpl: ValueBoxLogger {
func log(_ what: String) {
print("ValueBox: \(what)")
}
}*/
enum SyncProviderImpl {
static func isLocked(withRootPath rootPath: String) -> Bool {
if let data = try? Data(contentsOf: URL(fileURLWithPath: appLockStatePath(rootPath: rootPath))), let state = try? JSONDecoder().decode(LockState.self, from: data), isAppLocked(state: state) {
return true
} else {
return false
}
}
static func lockedMessageText(withRootPath rootPath: String) -> String {
if let data = try? Data(contentsOf: URL(fileURLWithPath: notificationsPresentationDataPath(rootPath: rootPath))), let value = try? JSONDecoder().decode(NotificationsPresentationData.self, from: data) {
return value.applicationLockedMessageString
} else {
return "You have a new message"
}
}
/*static func addIncomingMessage(queue: Queue, withRootPath rootPath: String, accountId: Int64, encryptionParameters: DeviceSpecificEncryptionParameters, peerId: Int64, messageId: Int32, completion: @escaping (Int32) -> Void) {
queue.async {
let _ = registeredTypes
let sharedBasePath = rootPath + "/accounts-metadata"
let basePath = rootPath + "/" + accountRecordIdPathName(accountId) + "/postbox"
let sharedValueBox = SqliteValueBox(basePath: sharedBasePath + "/db", queue: queue, logger: ValueBoxLoggerImpl(), encryptionParameters: nil, disableCache: true, upgradeProgress: { _ in
})
let valueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, logger: ValueBoxLoggerImpl(), encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: encryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: encryptionParameters.salt)!), disableCache: true, upgradeProgress: { _ in
})
let metadataTable = MessageHistoryMetadataTable(valueBox: valueBox, table: MessageHistoryMetadataTable.tableSpec(10))
let readStateTable = MessageHistoryReadStateTable(valueBox: valueBox, table: MessageHistoryReadStateTable.tableSpec(14), defaultMessageNamespaceReadStates: [:])
let peerTable = PeerTable(valueBox: valueBox, table: PeerTable.tableSpec(2), reverseAssociatedTable: nil)
let preferencesTable = PreferencesTable(valueBox: sharedValueBox, table: PreferencesTable.tableSpec(2))
let peerId = PeerId(peerId)
let initialCombinedState = readStateTable.getCombinedState(peerId)
let combinedState = initialCombinedState.flatMap { state -> CombinedPeerReadState in
var state = state
for i in 0 ..< state.states.count {
if state.states[i].0 == Namespaces.Message.Cloud {
switch state.states[i].1 {
case .idBased(let maxIncomingReadId, let maxOutgoingReadId, var maxKnownId, var count, let markedUnread):
if messageId > maxIncomingReadId {
count += 1
}
maxKnownId = max(maxKnownId, messageId)
state.states[i] = (state.states[i].0, .idBased(maxIncomingReadId: maxIncomingReadId, maxOutgoingReadId: maxOutgoingReadId, maxKnownId: maxKnownId, count: count, markedUnread: markedUnread))
default:
break
}
}
}
return state
}
if let combinedState = combinedState {
let initialCount = initialCombinedState?.count ?? 0
let updatedCount = combinedState.count
let deltaCount = max(0, updatedCount - initialCount)
let tag: PeerSummaryCounterTags
if peerId.namespace == Namespaces.Peer.CloudChannel {
if let channel = peerTable.get(peerId) as? TelegramChannel {
switch channel.info {
case .broadcast:
tag = .channel
case .group:
if channel.username != nil {
tag = .publicGroup
} else {
tag = .privateGroup
}
}
} else {
tag = .channel
}
} else if peerId.namespace == Namespaces.Peer.CloudGroup {
tag = .privateGroup
} else {
tag = .privateChat
}
var totalCount: Int32 = -1
var totalUnreadState = metadataTable.getChatListTotalUnreadState()
if var counters = totalUnreadState.absoluteCounters[tag] {
if initialCount == 0 && updatedCount > 0 {
counters.chatCount += 1
}
counters.messageCount += deltaCount
totalUnreadState.absoluteCounters[tag] = counters
}
if var counters = totalUnreadState.filteredCounters[tag] {
if initialCount == 0 && updatedCount > 0 {
counters.chatCount += 1
}
counters.messageCount += deltaCount
totalUnreadState.filteredCounters[tag] = counters
}
let inAppSettings = preferencesTable.get(key: ApplicationSpecificSharedDataKeys.inAppNotificationSettings) as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings
totalCount = totalUnreadState.count(for: inAppSettings.totalUnreadCountDisplayStyle.category, in: inAppSettings.totalUnreadCountDisplayCategory.statsType, with: inAppSettings.totalUnreadCountIncludeTags)
metadataTable.setChatListTotalUnreadState(totalUnreadState)
metadataTable.setShouldReindexUnreadCounts(value: true)
metadataTable.beforeCommit()
readStateTable.beforeCommit()
completion(totalCount)
} else {
completion(-1)
}
}
}*/
}

View File

@ -1,39 +0,0 @@
/*import PostboxDataTypes
import PostboxCoding
public enum TelegramChannelInfo: Int32 {
case broadcast = 0
case group = 1
}
public final class TelegramChannel: Peer {
public let id: PeerId
public let username: String?
public let info: TelegramChannelInfo
public let associatedPeerId: PeerId? = nil
public let notificationSettingsPeerId: PeerId? = nil
public init(decoder: PostboxDecoder) {
self.id = PeerId(decoder.decodeInt64ForKey("i", orElse: 0))
self.username = decoder.decodeOptionalStringForKey("un")
self.info = TelegramChannelInfo(rawValue: decoder.decodeInt32ForKey("i.t", orElse: 0)) ?? .broadcast
}
public func encode(_ encoder: PostboxEncoder) {
preconditionFailure()
}
public func isEqual(_ other: Peer) -> Bool {
guard let other = other as? TelegramChannel else {
return false
}
if self.username != other.username {
return false
}
return true
}
}
*/

View File

@ -121,7 +121,7 @@ class DefaultIntentHandler: INExtension, INSendMessageIntentHandling, INSearchFo
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
initializeAccountManagement()
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false)
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false, useCaches: false)
self.accountManager = accountManager
let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId)

View File

@ -386,14 +386,14 @@ static int32_t fixedTimeDifferenceValue = 0;
NSDictionary *datacenterAuthInfoById = [keychain objectForKey:@"datacenterAuthInfoById" group:@"persistent"];
if (datacenterAuthInfoById != nil) {
_datacenterAuthInfoById = [[NSMutableDictionary alloc] initWithDictionary:datacenterAuthInfoById];
#if DEBUG
/*#if DEBUG
NSArray<NSNumber *> *keys = [_datacenterAuthInfoById allKeys];
for (NSNumber *key in keys) {
if (parseAuthInfoMapKeyInteger(key).selector != MTDatacenterAuthInfoSelectorPersistent) {
[_datacenterAuthInfoById removeObjectForKey:key];
}
}
#endif
#endif*/
}
NSDictionary *datacenterPublicKeysById = [keychain objectForKey:@"datacenterPublicKeysById" group:@"ephemeral"];

View File

@ -69,7 +69,7 @@ final class AccountManagerImpl<Types: AccountManagerTypes> {
}
}
fileprivate init?(queue: Queue, basePath: String, isTemporary: Bool, isReadOnly: Bool, temporarySessionId: Int64) {
fileprivate init?(queue: Queue, basePath: String, isTemporary: Bool, isReadOnly: Bool, useCaches: Bool, temporarySessionId: Int64) {
let startTime = CFAbsoluteTimeGetCurrent()
self.queue = queue
@ -77,19 +77,19 @@ final class AccountManagerImpl<Types: AccountManagerTypes> {
self.atomicStatePath = "\(basePath)/atomic-state"
self.temporarySessionId = temporarySessionId
let _ = try? FileManager.default.createDirectory(atPath: basePath, withIntermediateDirectories: true, attributes: nil)
guard let guardValueBox = SqliteValueBox(basePath: basePath + "/guard_db", queue: queue, isTemporary: isTemporary, isReadOnly: false, encryptionParameters: nil, upgradeProgress: { _ in }) else {
guard let guardValueBox = SqliteValueBox(basePath: basePath + "/guard_db", queue: queue, isTemporary: isTemporary, isReadOnly: false, useCaches: useCaches, encryptionParameters: nil, upgradeProgress: { _ in }) else {
return nil
}
self.guardValueBox = guardValueBox
guard let valueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: nil, upgradeProgress: { _ in }) else {
guard let valueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, encryptionParameters: nil, upgradeProgress: { _ in }) else {
return nil
}
self.valueBox = valueBox
self.legacyMetadataTable = AccountManagerMetadataTable<Types.Attribute>(valueBox: self.valueBox, table: AccountManagerMetadataTable<Types.Attribute>.tableSpec(0))
self.legacyRecordTable = AccountManagerRecordTable<Types.Attribute>(valueBox: self.valueBox, table: AccountManagerRecordTable<Types.Attribute>.tableSpec(1))
self.sharedDataTable = AccountManagerSharedDataTable(valueBox: self.valueBox, table: AccountManagerSharedDataTable.tableSpec(2))
self.noticeTable = NoticeTable(valueBox: self.valueBox, table: NoticeTable.tableSpec(3))
self.legacyMetadataTable = AccountManagerMetadataTable<Types.Attribute>(valueBox: self.valueBox, table: AccountManagerMetadataTable<Types.Attribute>.tableSpec(0), useCaches: useCaches)
self.legacyRecordTable = AccountManagerRecordTable<Types.Attribute>(valueBox: self.valueBox, table: AccountManagerRecordTable<Types.Attribute>.tableSpec(1), useCaches: useCaches)
self.sharedDataTable = AccountManagerSharedDataTable(valueBox: self.valueBox, table: AccountManagerSharedDataTable.tableSpec(2), useCaches: useCaches)
self.noticeTable = NoticeTable(valueBox: self.valueBox, table: NoticeTable.tableSpec(3), useCaches: useCaches)
do {
let data = try Data(contentsOf: URL(fileURLWithPath: self.atomicStatePath))
@ -472,7 +472,7 @@ public final class AccountManager<Types: AccountManagerTypes> {
return AccountManagerImpl<Types>.getCurrentRecords(basePath: basePath)
}
public init(basePath: String, isTemporary: Bool, isReadOnly: Bool) {
public init(basePath: String, isTemporary: Bool, isReadOnly: Bool, useCaches: Bool) {
self.queue = sharedQueue
self.basePath = basePath
var temporarySessionId: Int64 = 0
@ -480,7 +480,7 @@ public final class AccountManager<Types: AccountManagerTypes> {
self.temporarySessionId = temporarySessionId
let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: {
if let value = AccountManagerImpl<Types>(queue: queue, basePath: basePath, isTemporary: isTemporary, isReadOnly: isReadOnly, temporarySessionId: temporarySessionId) {
if let value = AccountManagerImpl<Types>(queue: queue, basePath: basePath, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, temporarySessionId: temporarySessionId) {
return value
} else {
preconditionFailure()

View File

@ -11,8 +11,8 @@ final class CachedPeerDataTable: Table {
private var cachedDatas: [PeerId: CachedPeerData] = [:]
private var updatedPeerIds = Set<PeerId>()
override init(valueBox: ValueBox, table: ValueBoxTable) {
super.init(valueBox: valueBox, table: table)
override init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool) {
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(_ id: PeerId) -> ValueBoxKey {
@ -54,5 +54,8 @@ final class CachedPeerDataTable: Table {
}
self.updatedPeerIds.removeAll()
if !self.useCaches {
self.cachedDatas.removeAll()
}
}
}

View File

@ -52,13 +52,13 @@ final class ChatListIndexTable: Table {
private var updatedPreviousPeerCachedIndices: [PeerId: ChatListPeerInclusionIndex] = [:]
init(valueBox: ValueBox, table: ValueBoxTable, peerNameIndexTable: PeerNameIndexTable, metadataTable: MessageHistoryMetadataTable, readStateTable: MessageHistoryReadStateTable, notificationSettingsTable: PeerNotificationSettingsTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, peerNameIndexTable: PeerNameIndexTable, metadataTable: MessageHistoryMetadataTable, readStateTable: MessageHistoryReadStateTable, notificationSettingsTable: PeerNotificationSettingsTable) {
self.peerNameIndexTable = peerNameIndexTable
self.metadataTable = metadataTable
self.readStateTable = readStateTable
self.notificationSettingsTable = notificationSettingsTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(_ peerId: PeerId) -> ValueBoxKey {
@ -554,6 +554,10 @@ final class ChatListIndexTable: Table {
override func beforeCommit() {
assert(self.updatedPreviousPeerCachedIndices.isEmpty)
if !self.useCaches {
self.cachedPeerIndices.removeAll()
}
}
func debugReindexUnreadCounts(postbox: Postbox, currentTransaction: Transaction) -> ([PeerGroupId: ChatListTotalUnreadState], [PeerGroupId: PeerGroupUnreadCountersCombinedSummary]) {

View File

@ -133,12 +133,12 @@ final class ChatListTable: Table {
let metadataTable: MessageHistoryMetadataTable
let seedConfiguration: SeedConfiguration
init(valueBox: ValueBox, table: ValueBoxTable, indexTable: ChatListIndexTable, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, indexTable: ChatListIndexTable, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) {
self.indexTable = indexTable
self.metadataTable = metadataTable
self.seedConfiguration = seedConfiguration
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(groupId: PeerGroupId, index: ChatListIndex, type: ChatListEntryType) -> ValueBoxKey {

View File

@ -10,10 +10,10 @@ final class ContactTable: Table {
private var peerIdsBeforeModification: Set<PeerId>?
private var peerIds: Set<PeerId>?
init(valueBox: ValueBox, table: ValueBoxTable, peerNameIndexTable: PeerNameIndexTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, peerNameIndexTable: PeerNameIndexTable) {
self.peerNameIndexTable = peerNameIndexTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(_ id: PeerId, sharedKey: ValueBoxKey = ValueBoxKey(length: 8)) -> ValueBoxKey {
@ -98,5 +98,9 @@ final class ContactTable: Table {
self.peerIdsBeforeModification = nil
}
if !self.useCaches {
self.peerIds = nil
}
}
}

View File

@ -10,10 +10,10 @@ final class GlobalMessageIdsTable: Table {
private let sharedKey = ValueBoxKey(length: 8)
private let sharedBuffer = WriteBuffer()
init(valueBox: ValueBox, table: ValueBoxTable, seedConfiguration: SeedConfiguration) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration) {
self.seedConfiguration = seedConfiguration
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(_ id: Int32) -> ValueBoxKey {

View File

@ -63,9 +63,9 @@ final class ItemCollectionItemTable: Table {
private let sharedKey = ValueBoxKey(length: 4 + 8 + 4 + 8)
init(valueBox: ValueBox, table: ValueBoxTable, reverseIndexTable: ReverseIndexReferenceTable<ItemCollectionItemReverseIndexReference>) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, reverseIndexTable: ReverseIndexReferenceTable<ItemCollectionItemReverseIndexReference>) {
self.reverseIndexTable = reverseIndexTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(collectionId: ItemCollectionId, index: ItemCollectionItemIndex) -> ValueBoxKey {

View File

@ -49,11 +49,11 @@ final class MessageHistoryHoleIndexTable: Table {
let metadataTable: MessageHistoryMetadataTable
let seedConfiguration: SeedConfiguration
init(valueBox: ValueBox, table: ValueBoxTable, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) {
self.seedConfiguration = seedConfiguration
self.metadataTable = metadataTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(id: MessageId, space: MessageHistoryHoleSpace) -> ValueBoxKey {

View File

@ -47,13 +47,13 @@ final class MessageHistoryIndexTable: Table {
private var cachedExistingNamespaces: [PeerId: Set<MessageId.Namespace>] = [:]
init(valueBox: ValueBox, table: ValueBoxTable, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, globalMessageIdsTable: GlobalMessageIdsTable, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, globalMessageIdsTable: GlobalMessageIdsTable, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) {
self.messageHistoryHoleIndexTable = messageHistoryHoleIndexTable
self.globalMessageIdsTable = globalMessageIdsTable
self.seedConfiguration = seedConfiguration
self.metadataTable = metadataTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(_ id: MessageId) -> ValueBoxKey {

View File

@ -32,10 +32,10 @@ final class MessageHistoryReadStateTable: Table {
return self.sharedKey
}
init(valueBox: ValueBox, table: ValueBoxTable, seedConfiguration: SeedConfiguration) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration) {
self.seedConfiguration = seedConfiguration
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func get(_ id: PeerId) -> InternalPeerReadStates? {
@ -567,6 +567,10 @@ final class MessageHistoryReadStateTable: Table {
}
}
self.updatedInitialPeerReadStates.removeAll()
if !self.useCaches {
self.cachedPeerReadStates.removeAll()
}
}
}
}

View File

@ -90,7 +90,7 @@ final class MessageHistoryTable: Table {
let summaryTable: MessageHistoryTagsSummaryTable
let pendingActionsTable: PendingMessageActionsTable
init(valueBox: ValueBox, table: ValueBoxTable, seedConfiguration: SeedConfiguration, messageHistoryIndexTable: MessageHistoryIndexTable, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, messageMediaTable: MessageMediaTable, historyMetadataTable: MessageHistoryMetadataTable, globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable, unsentTable: MessageHistoryUnsentTable, failedTable: MessageHistoryFailedTable, tagsTable: MessageHistoryTagsTable, threadsTable: MessageHistoryThreadsTable, globalTagsTable: GlobalMessageHistoryTagsTable, localTagsTable: LocalMessageHistoryTagsTable, timeBasedAttributesTable: TimestampBasedMessageAttributesTable, readStateTable: MessageHistoryReadStateTable, synchronizeReadStateTable: MessageHistorySynchronizeReadStateTable, textIndexTable: MessageHistoryTextIndexTable, summaryTable: MessageHistoryTagsSummaryTable, pendingActionsTable: PendingMessageActionsTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration, messageHistoryIndexTable: MessageHistoryIndexTable, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, messageMediaTable: MessageMediaTable, historyMetadataTable: MessageHistoryMetadataTable, globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable, unsentTable: MessageHistoryUnsentTable, failedTable: MessageHistoryFailedTable, tagsTable: MessageHistoryTagsTable, threadsTable: MessageHistoryThreadsTable, globalTagsTable: GlobalMessageHistoryTagsTable, localTagsTable: LocalMessageHistoryTagsTable, timeBasedAttributesTable: TimestampBasedMessageAttributesTable, readStateTable: MessageHistoryReadStateTable, synchronizeReadStateTable: MessageHistorySynchronizeReadStateTable, textIndexTable: MessageHistoryTextIndexTable, summaryTable: MessageHistoryTagsSummaryTable, pendingActionsTable: PendingMessageActionsTable) {
self.seedConfiguration = seedConfiguration
self.messageHistoryIndexTable = messageHistoryIndexTable
self.messageHistoryHoleIndexTable = messageHistoryHoleIndexTable
@ -110,7 +110,7 @@ final class MessageHistoryTable: Table {
self.summaryTable = summaryTable
self.pendingActionsTable = pendingActionsTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(_ index: MessageIndex, key: ValueBoxKey = ValueBoxKey(length: 8 + 4 + 4 + 4)) -> ValueBoxKey {

View File

@ -82,10 +82,10 @@ class MessageHistoryTagsSummaryTable: Table {
private let sharedKey = ValueBoxKey(length: 4 + 8 + 4)
init(valueBox: ValueBox, table: ValueBoxTable, invalidateTable: InvalidatedMessageHistoryTagsSummaryTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, invalidateTable: InvalidatedMessageHistoryTagsSummaryTable) {
self.invalidateTable = invalidateTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(key: MessageHistoryTagsSummaryKey, sharedKey: ValueBoxKey = ValueBoxKey(length: 4 + 8 + 4)) -> ValueBoxKey {
@ -172,5 +172,9 @@ class MessageHistoryTagsSummaryTable: Table {
}
self.updatedKeys.removeAll()
}
if !self.useCaches {
self.cachedSummaries.removeAll()
}
}
}

View File

@ -14,11 +14,11 @@ class MessageHistoryTagsTable: Table {
private let summaryTable: MessageHistoryTagsSummaryTable
private let summaryTags: MessageTags
init(valueBox: ValueBox, table: ValueBoxTable, seedConfiguration: SeedConfiguration, summaryTable: MessageHistoryTagsSummaryTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration, summaryTable: MessageHistoryTagsSummaryTable) {
self.summaryTable = summaryTable
self.summaryTags = seedConfiguration.messageTagsWithSummary
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(tag: MessageTags, index: MessageIndex, key: ValueBoxKey = ValueBoxKey(length: 8 + 4 + 4 + 4 + 4)) -> ValueBoxKey {

View File

@ -25,11 +25,11 @@ final class MessageHistoryThreadHoleIndexTable: Table {
let metadataTable: MessageHistoryMetadataTable
let seedConfiguration: SeedConfiguration
init(valueBox: ValueBox, table: ValueBoxTable, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) {
self.seedConfiguration = seedConfiguration
self.metadataTable = metadataTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(threadId: Int64, id: MessageId, space: MessageHistoryHoleSpace) -> ValueBoxKey {

View File

@ -11,8 +11,8 @@ class MessageHistoryThreadsTable: Table {
private let sharedKey = ValueBoxKey(length: 8 + 8 + 4 + 4 + 4)
override init(valueBox: ValueBox, table: ValueBoxTable) {
super.init(valueBox: valueBox, table: table)
override init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool) {
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(threadId: Int64, index: MessageIndex, key: ValueBoxKey = ValueBoxKey(length: 8 + 8 + 4 + 4 + 4)) -> ValueBoxKey {

View File

@ -19,8 +19,8 @@ final class MetadataTable: Table {
private let sharedBuffer = WriteBuffer()
override init(valueBox: ValueBox, table: ValueBoxTable) {
super.init(valueBox: valueBox, table: table)
override init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool) {
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(_ key: MetadataKey) -> ValueBoxKey {

View File

@ -19,10 +19,10 @@ final class OrderedItemListTable: Table {
private let indexTable: OrderedItemListIndexTable
init(valueBox: ValueBox, table: ValueBoxTable, indexTable: OrderedItemListIndexTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, indexTable: OrderedItemListIndexTable) {
self.indexTable = indexTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func keyIndexToId(collectionId: Int32, itemIndex: UInt32) -> ValueBoxKey {

View File

@ -7,10 +7,10 @@ final class PeerMergedOperationLogIndexTable: Table {
private let metadataTable: PeerOperationLogMetadataTable
init(valueBox: ValueBox, table: ValueBoxTable, metadataTable: PeerOperationLogMetadataTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, metadataTable: PeerOperationLogMetadataTable) {
self.metadataTable = metadataTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(tag: PeerOperationLogTag, index: Int32) -> ValueBoxKey {

View File

@ -140,11 +140,11 @@ final class PeerNameIndexTable: Table {
private var entryUpdates: [PeerId: PeerNameIndexCategoriesEntryUpdate] = [:]
init(valueBox: ValueBox, table: ValueBoxTable, peerTable: PeerTable, peerNameTokenIndexTable: ReverseIndexReferenceTable<PeerIdReverseIndexReference>) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, peerTable: PeerTable, peerNameTokenIndexTable: ReverseIndexReferenceTable<PeerIdReverseIndexReference>) {
self.peerTable = peerTable
self.peerNameTokenIndexTable = peerNameTokenIndexTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(_ peerId: PeerId) -> ValueBoxKey {

View File

@ -11,10 +11,10 @@ final class PeerNotificationSettingsBehaviorTable: Table {
private let indexTable: PeerNotificationSettingsBehaviorIndexTable
init(valueBox: ValueBox, table: ValueBoxTable, indexTable: PeerNotificationSettingsBehaviorIndexTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, indexTable: PeerNotificationSettingsBehaviorIndexTable) {
self.indexTable = indexTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(peerId: PeerId, timestamp: Int32) -> ValueBoxKey {

View File

@ -63,11 +63,11 @@ final class PeerNotificationSettingsTable: Table {
private var cachedSettings: [PeerId: PeerNotificationSettingsTableEntry] = [:]
private var updatedInitialSettings: [PeerId: PeerNotificationSettingsTableEntry] = [:]
init(valueBox: ValueBox, table: ValueBoxTable, pendingIndexTable: PendingPeerNotificationSettingsIndexTable, behaviorTable: PeerNotificationSettingsBehaviorTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, pendingIndexTable: PendingPeerNotificationSettingsIndexTable, behaviorTable: PeerNotificationSettingsBehaviorTable) {
self.pendingIndexTable = pendingIndexTable
self.behaviorTable = behaviorTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(_ id: PeerId) -> ValueBoxKey {
@ -301,6 +301,10 @@ final class PeerNotificationSettingsTable: Table {
}
self.updatedInitialSettings.removeAll()
if !self.useCaches {
self.cachedSettings.removeAll()
}
}
}
}

View File

@ -112,11 +112,11 @@ final class PeerOperationLogTable: Table {
private let metadataTable: PeerOperationLogMetadataTable
private let mergedIndexTable: PeerMergedOperationLogIndexTable
init(valueBox: ValueBox, table: ValueBoxTable, metadataTable: PeerOperationLogMetadataTable, mergedIndexTable: PeerMergedOperationLogIndexTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, metadataTable: PeerOperationLogMetadataTable, mergedIndexTable: PeerMergedOperationLogIndexTable) {
self.metadataTable = metadataTable
self.mergedIndexTable = mergedIndexTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(peerId: PeerId, tag: PeerOperationLogTag, index: Int32) -> ValueBoxKey {

View File

@ -13,10 +13,10 @@ final class PeerTable: Table {
private var cachedPeers: [PeerId: Peer] = [:]
private var updatedInitialPeers: [PeerId: Peer?] = [:]
init(valueBox: ValueBox, table: ValueBoxTable, reverseAssociatedTable: ReverseAssociatedPeerTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, reverseAssociatedTable: ReverseAssociatedPeerTable) {
self.reverseAssociatedTable = reverseAssociatedTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(_ id: PeerId) -> ValueBoxKey {
@ -87,6 +87,9 @@ final class PeerTable: Table {
}
self.updatedInitialPeers.removeAll()
if !self.useCaches {
self.cachedPeers.removeAll()
}
}
}
}

View File

@ -53,10 +53,10 @@ final class PendingMessageActionsTable: Table {
private let metadataTable: PendingMessageActionsMetadataTable
init(valueBox: ValueBox, table: ValueBoxTable, metadataTable: PendingMessageActionsMetadataTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, metadataTable: PendingMessageActionsMetadataTable) {
self.metadataTable = metadataTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func forwardKey(id: MessageId, actionType: PendingMessageActionType) -> ValueBoxKey {

View File

@ -1165,7 +1165,7 @@ func debugRestoreState(basePath:String, name: String) {
private let sharedQueue = Queue(name: "org.telegram.postbox.Postbox")
public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, encryptionParameters: ValueBoxEncryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool, isReadOnly: Bool, useCopy: Bool) -> Signal<PostboxResult, NoError> {
public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, encryptionParameters: ValueBoxEncryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool, isReadOnly: Bool, useCopy: Bool, useCaches: Bool) -> Signal<PostboxResult, NoError> {
let queue = sharedQueue
return Signal { subscriber in
queue.async {
@ -1209,7 +1209,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
postboxLog("openPostbox, initialize SqliteValueBox")
guard var valueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: encryptionParameters, upgradeProgress: { progress in
guard var valueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, encryptionParameters: encryptionParameters, upgradeProgress: { progress in
postboxLog("openPostbox, SqliteValueBox upgrading progress \(progress)")
subscriber.putNext(.upgrading(progress))
}) else {
@ -1219,7 +1219,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
}
loop: while true {
let metadataTable = MetadataTable(valueBox: valueBox, table: MetadataTable.tableSpec(0))
let metadataTable = MetadataTable(valueBox: valueBox, table: MetadataTable.tableSpec(0), useCaches: useCaches)
let userVersion: Int32? = metadataTable.userVersion()
let currentUserVersion: Int32 = 25
@ -1237,7 +1237,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
postboxLog("Version \(userVersion) is newer than supported")
assertionFailure("Version \(userVersion) is newer than supported")
valueBox.drop()
guard let updatedValueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: encryptionParameters, upgradeProgress: { progress in
guard let updatedValueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, encryptionParameters: encryptionParameters, upgradeProgress: { progress in
subscriber.putNext(.upgrading(progress))
}) else {
subscriber.putNext(.error)
@ -1261,7 +1261,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
valueBox.internalClose()
let _ = try? FileManager.default.removeItem(atPath: dbBasePath)
let _ = try? FileManager.default.moveItem(atPath: updatedPath, toPath: dbBasePath)
guard let updatedValueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: encryptionParameters, upgradeProgress: { progress in
guard let updatedValueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, encryptionParameters: encryptionParameters, upgradeProgress: { progress in
subscriber.putNext(.upgrading(progress))
}) else {
subscriber.putNext(.error)
@ -1275,7 +1275,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
assertionFailure("Couldn't find any upgrade for \(userVersion)")
postboxLog("Couldn't find any upgrade for \(userVersion)")
valueBox.drop()
guard let updatedValueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: encryptionParameters, upgradeProgress: { progress in
guard let updatedValueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, encryptionParameters: encryptionParameters, upgradeProgress: { progress in
subscriber.putNext(.upgrading(progress))
}) else {
subscriber.putNext(.error)
@ -1293,7 +1293,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
let endTime = CFAbsoluteTimeGetCurrent()
postboxLog("Postbox load took \((endTime - startTime) * 1000.0) ms")
subscriber.putNext(.postbox(Postbox(queue: queue, basePath: basePath, seedConfiguration: seedConfiguration, valueBox: valueBox, timestampForAbsoluteTimeBasedOperations: timestampForAbsoluteTimeBasedOperations, isTemporary: isTemporary, tempDir: tempDir)))
subscriber.putNext(.postbox(Postbox(queue: queue, basePath: basePath, seedConfiguration: seedConfiguration, valueBox: valueBox, timestampForAbsoluteTimeBasedOperations: timestampForAbsoluteTimeBasedOperations, isTemporary: isTemporary, tempDir: tempDir, useCaches: useCaches)))
postboxLog("openPostbox, putCompletion")
@ -1450,7 +1450,7 @@ public final class Postbox {
var installedMessageActionsByPeerId: [PeerId: Bag<([StoreMessage], Transaction) -> Void>] = [:]
init(queue: Queue, basePath: String, seedConfiguration: SeedConfiguration, valueBox: SqliteValueBox, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool, tempDir: TempBoxDirectory?) {
init(queue: Queue, basePath: String, seedConfiguration: SeedConfiguration, valueBox: SqliteValueBox, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool, tempDir: TempBoxDirectory?, useCaches: Bool) {
assert(queue.isCurrent())
let startTime = CFAbsoluteTimeGetCurrent()
@ -1465,67 +1465,67 @@ public final class Postbox {
self.mediaBox = MediaBox(basePath: self.basePath + "/media")
self.valueBox = valueBox
self.metadataTable = MetadataTable(valueBox: self.valueBox, table: MetadataTable.tableSpec(0))
self.metadataTable = MetadataTable(valueBox: self.valueBox, table: MetadataTable.tableSpec(0), useCaches: useCaches)
self.keychainTable = KeychainTable(valueBox: self.valueBox, table: KeychainTable.tableSpec(1))
self.reverseAssociatedPeerTable = ReverseAssociatedPeerTable(valueBox: self.valueBox, table:ReverseAssociatedPeerTable.tableSpec(40))
self.peerTable = PeerTable(valueBox: self.valueBox, table: PeerTable.tableSpec(2), reverseAssociatedTable: self.reverseAssociatedPeerTable)
self.globalMessageIdsTable = GlobalMessageIdsTable(valueBox: self.valueBox, table: GlobalMessageIdsTable.tableSpec(3), seedConfiguration: seedConfiguration)
self.globallyUniqueMessageIdsTable = MessageGloballyUniqueIdTable(valueBox: self.valueBox, table: MessageGloballyUniqueIdTable.tableSpec(32))
self.messageHistoryMetadataTable = MessageHistoryMetadataTable(valueBox: self.valueBox, table: MessageHistoryMetadataTable.tableSpec(10))
self.messageHistoryHoleIndexTable = MessageHistoryHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryHoleIndexTable.tableSpec(56), metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
self.messageHistoryUnsentTable = MessageHistoryUnsentTable(valueBox: self.valueBox, table: MessageHistoryUnsentTable.tableSpec(11))
self.messageHistoryFailedTable = MessageHistoryFailedTable(valueBox: self.valueBox, table: MessageHistoryFailedTable.tableSpec(49))
self.invalidatedMessageHistoryTagsSummaryTable = InvalidatedMessageHistoryTagsSummaryTable(valueBox: self.valueBox, table: InvalidatedMessageHistoryTagsSummaryTable.tableSpec(47))
self.messageHistoryTagsSummaryTable = MessageHistoryTagsSummaryTable(valueBox: self.valueBox, table: MessageHistoryTagsSummaryTable.tableSpec(44), invalidateTable: self.invalidatedMessageHistoryTagsSummaryTable)
self.pendingMessageActionsMetadataTable = PendingMessageActionsMetadataTable(valueBox: self.valueBox, table: PendingMessageActionsMetadataTable.tableSpec(45))
self.pendingMessageActionsTable = PendingMessageActionsTable(valueBox: self.valueBox, table: PendingMessageActionsTable.tableSpec(46), metadataTable: self.pendingMessageActionsMetadataTable)
self.messageHistoryTagsTable = MessageHistoryTagsTable(valueBox: self.valueBox, table: MessageHistoryTagsTable.tableSpec(12), seedConfiguration: self.seedConfiguration, summaryTable: self.messageHistoryTagsSummaryTable)
self.messageHistoryThreadsTable = MessageHistoryThreadsTable(valueBox: self.valueBox, table: MessageHistoryThreadsTable.tableSpec(62))
self.messageHistoryThreadHoleIndexTable = MessageHistoryThreadHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadHoleIndexTable.tableSpec(63), metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
self.globalMessageHistoryTagsTable = GlobalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(39))
self.localMessageHistoryTagsTable = LocalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(52))
self.messageHistoryIndexTable = MessageHistoryIndexTable(valueBox: self.valueBox, table: MessageHistoryIndexTable.tableSpec(4), messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, globalMessageIdsTable: self.globalMessageIdsTable, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
self.mediaTable = MessageMediaTable(valueBox: self.valueBox, table: MessageMediaTable.tableSpec(6))
self.readStateTable = MessageHistoryReadStateTable(valueBox: self.valueBox, table: MessageHistoryReadStateTable.tableSpec(14), seedConfiguration: seedConfiguration)
self.synchronizeReadStateTable = MessageHistorySynchronizeReadStateTable(valueBox: self.valueBox, table: MessageHistorySynchronizeReadStateTable.tableSpec(15))
self.synchronizeGroupMessageStatsTable = InvalidatedGroupMessageStatsTable(valueBox: self.valueBox, table: InvalidatedGroupMessageStatsTable.tableSpec(59))
self.timestampBasedMessageAttributesIndexTable = TimestampBasedMessageAttributesIndexTable(valueBox: self.valueBox, table: TimestampBasedMessageAttributesTable.tableSpec(33))
self.timestampBasedMessageAttributesTable = TimestampBasedMessageAttributesTable(valueBox: self.valueBox, table: TimestampBasedMessageAttributesTable.tableSpec(34), indexTable: self.timestampBasedMessageAttributesIndexTable)
self.keychainTable = KeychainTable(valueBox: self.valueBox, table: KeychainTable.tableSpec(1), useCaches: useCaches)
self.reverseAssociatedPeerTable = ReverseAssociatedPeerTable(valueBox: self.valueBox, table:ReverseAssociatedPeerTable.tableSpec(40), useCaches: useCaches)
self.peerTable = PeerTable(valueBox: self.valueBox, table: PeerTable.tableSpec(2), useCaches: useCaches, reverseAssociatedTable: self.reverseAssociatedPeerTable)
self.globalMessageIdsTable = GlobalMessageIdsTable(valueBox: self.valueBox, table: GlobalMessageIdsTable.tableSpec(3), useCaches: useCaches, seedConfiguration: seedConfiguration)
self.globallyUniqueMessageIdsTable = MessageGloballyUniqueIdTable(valueBox: self.valueBox, table: MessageGloballyUniqueIdTable.tableSpec(32), useCaches: useCaches)
self.messageHistoryMetadataTable = MessageHistoryMetadataTable(valueBox: self.valueBox, table: MessageHistoryMetadataTable.tableSpec(10), useCaches: useCaches)
self.messageHistoryHoleIndexTable = MessageHistoryHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryHoleIndexTable.tableSpec(56), useCaches: useCaches, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
self.messageHistoryUnsentTable = MessageHistoryUnsentTable(valueBox: self.valueBox, table: MessageHistoryUnsentTable.tableSpec(11), useCaches: useCaches)
self.messageHistoryFailedTable = MessageHistoryFailedTable(valueBox: self.valueBox, table: MessageHistoryFailedTable.tableSpec(49), useCaches: useCaches)
self.invalidatedMessageHistoryTagsSummaryTable = InvalidatedMessageHistoryTagsSummaryTable(valueBox: self.valueBox, table: InvalidatedMessageHistoryTagsSummaryTable.tableSpec(47), useCaches: useCaches)
self.messageHistoryTagsSummaryTable = MessageHistoryTagsSummaryTable(valueBox: self.valueBox, table: MessageHistoryTagsSummaryTable.tableSpec(44), useCaches: useCaches, invalidateTable: self.invalidatedMessageHistoryTagsSummaryTable)
self.pendingMessageActionsMetadataTable = PendingMessageActionsMetadataTable(valueBox: self.valueBox, table: PendingMessageActionsMetadataTable.tableSpec(45), useCaches: useCaches)
self.pendingMessageActionsTable = PendingMessageActionsTable(valueBox: self.valueBox, table: PendingMessageActionsTable.tableSpec(46), useCaches: useCaches, metadataTable: self.pendingMessageActionsMetadataTable)
self.messageHistoryTagsTable = MessageHistoryTagsTable(valueBox: self.valueBox, table: MessageHistoryTagsTable.tableSpec(12), useCaches: useCaches, seedConfiguration: self.seedConfiguration, summaryTable: self.messageHistoryTagsSummaryTable)
self.messageHistoryThreadsTable = MessageHistoryThreadsTable(valueBox: self.valueBox, table: MessageHistoryThreadsTable.tableSpec(62), useCaches: useCaches)
self.messageHistoryThreadHoleIndexTable = MessageHistoryThreadHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadHoleIndexTable.tableSpec(63), useCaches: useCaches, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
self.globalMessageHistoryTagsTable = GlobalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(39), useCaches: useCaches)
self.localMessageHistoryTagsTable = LocalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(52), useCaches: useCaches)
self.messageHistoryIndexTable = MessageHistoryIndexTable(valueBox: self.valueBox, table: MessageHistoryIndexTable.tableSpec(4), useCaches: useCaches, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, globalMessageIdsTable: self.globalMessageIdsTable, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
self.mediaTable = MessageMediaTable(valueBox: self.valueBox, table: MessageMediaTable.tableSpec(6), useCaches: useCaches)
self.readStateTable = MessageHistoryReadStateTable(valueBox: self.valueBox, table: MessageHistoryReadStateTable.tableSpec(14), useCaches: useCaches, seedConfiguration: seedConfiguration)
self.synchronizeReadStateTable = MessageHistorySynchronizeReadStateTable(valueBox: self.valueBox, table: MessageHistorySynchronizeReadStateTable.tableSpec(15), useCaches: useCaches)
self.synchronizeGroupMessageStatsTable = InvalidatedGroupMessageStatsTable(valueBox: self.valueBox, table: InvalidatedGroupMessageStatsTable.tableSpec(59), useCaches: useCaches)
self.timestampBasedMessageAttributesIndexTable = TimestampBasedMessageAttributesIndexTable(valueBox: self.valueBox, table: TimestampBasedMessageAttributesTable.tableSpec(33), useCaches: useCaches)
self.timestampBasedMessageAttributesTable = TimestampBasedMessageAttributesTable(valueBox: self.valueBox, table: TimestampBasedMessageAttributesTable.tableSpec(34), useCaches: useCaches, indexTable: self.timestampBasedMessageAttributesIndexTable)
self.textIndexTable = MessageHistoryTextIndexTable(valueBox: self.valueBox, table: MessageHistoryTextIndexTable.tableSpec(41))
self.additionalChatListItemsTable = AdditionalChatListItemsTable(valueBox: self.valueBox, table: AdditionalChatListItemsTable.tableSpec(55))
self.messageHistoryTable = MessageHistoryTable(valueBox: self.valueBox, table: MessageHistoryTable.tableSpec(7), seedConfiguration: seedConfiguration, messageHistoryIndexTable: self.messageHistoryIndexTable, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, messageMediaTable: self.mediaTable, historyMetadataTable: self.messageHistoryMetadataTable, globallyUniqueMessageIdsTable: self.globallyUniqueMessageIdsTable, unsentTable: self.messageHistoryUnsentTable, failedTable: self.messageHistoryFailedTable, tagsTable: self.messageHistoryTagsTable, threadsTable: self.messageHistoryThreadsTable, globalTagsTable: self.globalMessageHistoryTagsTable, localTagsTable: self.localMessageHistoryTagsTable, timeBasedAttributesTable: self.timestampBasedMessageAttributesTable, readStateTable: self.readStateTable, synchronizeReadStateTable: self.synchronizeReadStateTable, textIndexTable: self.textIndexTable, summaryTable: self.messageHistoryTagsSummaryTable, pendingActionsTable: self.pendingMessageActionsTable)
self.peerChatStateTable = PeerChatStateTable(valueBox: self.valueBox, table: PeerChatStateTable.tableSpec(13))
self.peerNameTokenIndexTable = ReverseIndexReferenceTable<PeerIdReverseIndexReference>(valueBox: self.valueBox, table: ReverseIndexReferenceTable<PeerIdReverseIndexReference>.tableSpec(26))
self.peerNameIndexTable = PeerNameIndexTable(valueBox: self.valueBox, table: PeerNameIndexTable.tableSpec(27), peerTable: self.peerTable, peerNameTokenIndexTable: self.peerNameTokenIndexTable)
self.contactsTable = ContactTable(valueBox: self.valueBox, table: ContactTable.tableSpec(16), peerNameIndexTable: self.peerNameIndexTable)
self.peerRatingTable = RatingTable<PeerId>(valueBox: self.valueBox, table: RatingTable<PeerId>.tableSpec(17))
self.cachedPeerDataTable = CachedPeerDataTable(valueBox: self.valueBox, table: CachedPeerDataTable.tableSpec(18))
self.pendingPeerNotificationSettingsIndexTable = PendingPeerNotificationSettingsIndexTable(valueBox: self.valueBox, table: PendingPeerNotificationSettingsIndexTable.tableSpec(48))
self.peerNotificationSettingsBehaviorIndexTable = PeerNotificationSettingsBehaviorIndexTable(valueBox: self.valueBox, table: PeerNotificationSettingsBehaviorIndexTable.tableSpec(60))
self.peerNotificationSettingsBehaviorTable = PeerNotificationSettingsBehaviorTable(valueBox: self.valueBox, table: PeerNotificationSettingsBehaviorTable.tableSpec(61), indexTable: self.peerNotificationSettingsBehaviorIndexTable)
self.peerNotificationSettingsTable = PeerNotificationSettingsTable(valueBox: self.valueBox, table: PeerNotificationSettingsTable.tableSpec(19), pendingIndexTable: self.pendingPeerNotificationSettingsIndexTable, behaviorTable: self.peerNotificationSettingsBehaviorTable)
self.peerPresenceTable = PeerPresenceTable(valueBox: self.valueBox, table: PeerPresenceTable.tableSpec(20))
self.itemCollectionInfoTable = ItemCollectionInfoTable(valueBox: self.valueBox, table: ItemCollectionInfoTable.tableSpec(21))
self.itemCollectionReverseIndexTable = ReverseIndexReferenceTable<ItemCollectionItemReverseIndexReference>(valueBox: self.valueBox, table: ReverseIndexReferenceTable<ItemCollectionItemReverseIndexReference>.tableSpec(36))
self.itemCollectionItemTable = ItemCollectionItemTable(valueBox: self.valueBox, table: ItemCollectionItemTable.tableSpec(22), reverseIndexTable: self.itemCollectionReverseIndexTable)
self.peerChatInterfaceStateTable = PeerChatInterfaceStateTable(valueBox: self.valueBox, table: PeerChatInterfaceStateTable.tableSpec(67))
self.peerChatThreadInterfaceStateTable = PeerChatThreadInterfaceStateTable(valueBox: self.valueBox, table: PeerChatThreadInterfaceStateTable.tableSpec(68))
self.itemCacheMetaTable = ItemCacheMetaTable(valueBox: self.valueBox, table: ItemCacheMetaTable.tableSpec(24))
self.itemCacheTable = ItemCacheTable(valueBox: self.valueBox, table: ItemCacheTable.tableSpec(25))
self.chatListIndexTable = ChatListIndexTable(valueBox: self.valueBox, table: ChatListIndexTable.tableSpec(8), peerNameIndexTable: self.peerNameIndexTable, metadataTable: self.messageHistoryMetadataTable, readStateTable: self.readStateTable, notificationSettingsTable: self.peerNotificationSettingsTable)
self.chatListTable = ChatListTable(valueBox: self.valueBox, table: ChatListTable.tableSpec(9), indexTable: self.chatListIndexTable, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
self.peerChatTopTaggedMessageIdsTable = PeerChatTopTaggedMessageIdsTable(valueBox: self.valueBox, table: PeerChatTopTaggedMessageIdsTable.tableSpec(28))
self.peerOperationLogMetadataTable = PeerOperationLogMetadataTable(valueBox: self.valueBox, table: PeerOperationLogMetadataTable.tableSpec(29))
self.peerMergedOperationLogIndexTable = PeerMergedOperationLogIndexTable(valueBox: self.valueBox, table: PeerMergedOperationLogIndexTable.tableSpec(30), metadataTable: self.peerOperationLogMetadataTable)
self.peerOperationLogTable = PeerOperationLogTable(valueBox: self.valueBox, table: PeerOperationLogTable.tableSpec(31), metadataTable: self.peerOperationLogMetadataTable, mergedIndexTable: self.peerMergedOperationLogIndexTable)
self.preferencesTable = PreferencesTable(valueBox: self.valueBox, table: PreferencesTable.tableSpec(35))
self.orderedItemListIndexTable = OrderedItemListIndexTable(valueBox: self.valueBox, table: OrderedItemListIndexTable.tableSpec(37))
self.orderedItemListTable = OrderedItemListTable(valueBox: self.valueBox, table: OrderedItemListTable.tableSpec(38), indexTable: self.orderedItemListIndexTable)
self.unorderedItemListTable = UnorderedItemListTable(valueBox: self.valueBox, table: UnorderedItemListTable.tableSpec(42))
self.noticeTable = NoticeTable(valueBox: self.valueBox, table: NoticeTable.tableSpec(43))
self.deviceContactImportInfoTable = DeviceContactImportInfoTable(valueBox: self.valueBox, table: DeviceContactImportInfoTable.tableSpec(54))
self.groupMessageStatsTable = GroupMessageStatsTable(valueBox: self.valueBox, table: GroupMessageStatsTable.tableSpec(58))
self.additionalChatListItemsTable = AdditionalChatListItemsTable(valueBox: self.valueBox, table: AdditionalChatListItemsTable.tableSpec(55), useCaches: useCaches)
self.messageHistoryTable = MessageHistoryTable(valueBox: self.valueBox, table: MessageHistoryTable.tableSpec(7), useCaches: useCaches, seedConfiguration: seedConfiguration, messageHistoryIndexTable: self.messageHistoryIndexTable, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, messageMediaTable: self.mediaTable, historyMetadataTable: self.messageHistoryMetadataTable, globallyUniqueMessageIdsTable: self.globallyUniqueMessageIdsTable, unsentTable: self.messageHistoryUnsentTable, failedTable: self.messageHistoryFailedTable, tagsTable: self.messageHistoryTagsTable, threadsTable: self.messageHistoryThreadsTable, globalTagsTable: self.globalMessageHistoryTagsTable, localTagsTable: self.localMessageHistoryTagsTable, timeBasedAttributesTable: self.timestampBasedMessageAttributesTable, readStateTable: self.readStateTable, synchronizeReadStateTable: self.synchronizeReadStateTable, textIndexTable: self.textIndexTable, summaryTable: self.messageHistoryTagsSummaryTable, pendingActionsTable: self.pendingMessageActionsTable)
self.peerChatStateTable = PeerChatStateTable(valueBox: self.valueBox, table: PeerChatStateTable.tableSpec(13), useCaches: useCaches)
self.peerNameTokenIndexTable = ReverseIndexReferenceTable<PeerIdReverseIndexReference>(valueBox: self.valueBox, table: ReverseIndexReferenceTable<PeerIdReverseIndexReference>.tableSpec(26), useCaches: useCaches)
self.peerNameIndexTable = PeerNameIndexTable(valueBox: self.valueBox, table: PeerNameIndexTable.tableSpec(27), useCaches: useCaches, peerTable: self.peerTable, peerNameTokenIndexTable: self.peerNameTokenIndexTable)
self.contactsTable = ContactTable(valueBox: self.valueBox, table: ContactTable.tableSpec(16), useCaches: useCaches, peerNameIndexTable: self.peerNameIndexTable)
self.peerRatingTable = RatingTable<PeerId>(valueBox: self.valueBox, table: RatingTable<PeerId>.tableSpec(17), useCaches: useCaches)
self.cachedPeerDataTable = CachedPeerDataTable(valueBox: self.valueBox, table: CachedPeerDataTable.tableSpec(18), useCaches: useCaches)
self.pendingPeerNotificationSettingsIndexTable = PendingPeerNotificationSettingsIndexTable(valueBox: self.valueBox, table: PendingPeerNotificationSettingsIndexTable.tableSpec(48), useCaches: useCaches)
self.peerNotificationSettingsBehaviorIndexTable = PeerNotificationSettingsBehaviorIndexTable(valueBox: self.valueBox, table: PeerNotificationSettingsBehaviorIndexTable.tableSpec(60), useCaches: useCaches)
self.peerNotificationSettingsBehaviorTable = PeerNotificationSettingsBehaviorTable(valueBox: self.valueBox, table: PeerNotificationSettingsBehaviorTable.tableSpec(61), useCaches: useCaches, indexTable: self.peerNotificationSettingsBehaviorIndexTable)
self.peerNotificationSettingsTable = PeerNotificationSettingsTable(valueBox: self.valueBox, table: PeerNotificationSettingsTable.tableSpec(19), useCaches: useCaches, pendingIndexTable: self.pendingPeerNotificationSettingsIndexTable, behaviorTable: self.peerNotificationSettingsBehaviorTable)
self.peerPresenceTable = PeerPresenceTable(valueBox: self.valueBox, table: PeerPresenceTable.tableSpec(20), useCaches: useCaches)
self.itemCollectionInfoTable = ItemCollectionInfoTable(valueBox: self.valueBox, table: ItemCollectionInfoTable.tableSpec(21), useCaches: useCaches)
self.itemCollectionReverseIndexTable = ReverseIndexReferenceTable<ItemCollectionItemReverseIndexReference>(valueBox: self.valueBox, table: ReverseIndexReferenceTable<ItemCollectionItemReverseIndexReference>.tableSpec(36), useCaches: useCaches)
self.itemCollectionItemTable = ItemCollectionItemTable(valueBox: self.valueBox, table: ItemCollectionItemTable.tableSpec(22), useCaches: useCaches, reverseIndexTable: self.itemCollectionReverseIndexTable)
self.peerChatInterfaceStateTable = PeerChatInterfaceStateTable(valueBox: self.valueBox, table: PeerChatInterfaceStateTable.tableSpec(67), useCaches: useCaches)
self.peerChatThreadInterfaceStateTable = PeerChatThreadInterfaceStateTable(valueBox: self.valueBox, table: PeerChatThreadInterfaceStateTable.tableSpec(68), useCaches: useCaches)
self.itemCacheMetaTable = ItemCacheMetaTable(valueBox: self.valueBox, table: ItemCacheMetaTable.tableSpec(24), useCaches: useCaches)
self.itemCacheTable = ItemCacheTable(valueBox: self.valueBox, table: ItemCacheTable.tableSpec(25), useCaches: useCaches)
self.chatListIndexTable = ChatListIndexTable(valueBox: self.valueBox, table: ChatListIndexTable.tableSpec(8), useCaches: useCaches, peerNameIndexTable: self.peerNameIndexTable, metadataTable: self.messageHistoryMetadataTable, readStateTable: self.readStateTable, notificationSettingsTable: self.peerNotificationSettingsTable)
self.chatListTable = ChatListTable(valueBox: self.valueBox, table: ChatListTable.tableSpec(9), useCaches: useCaches, indexTable: self.chatListIndexTable, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
self.peerChatTopTaggedMessageIdsTable = PeerChatTopTaggedMessageIdsTable(valueBox: self.valueBox, table: PeerChatTopTaggedMessageIdsTable.tableSpec(28), useCaches: useCaches)
self.peerOperationLogMetadataTable = PeerOperationLogMetadataTable(valueBox: self.valueBox, table: PeerOperationLogMetadataTable.tableSpec(29), useCaches: useCaches)
self.peerMergedOperationLogIndexTable = PeerMergedOperationLogIndexTable(valueBox: self.valueBox, table: PeerMergedOperationLogIndexTable.tableSpec(30), useCaches: useCaches, metadataTable: self.peerOperationLogMetadataTable)
self.peerOperationLogTable = PeerOperationLogTable(valueBox: self.valueBox, table: PeerOperationLogTable.tableSpec(31), useCaches: useCaches, metadataTable: self.peerOperationLogMetadataTable, mergedIndexTable: self.peerMergedOperationLogIndexTable)
self.preferencesTable = PreferencesTable(valueBox: self.valueBox, table: PreferencesTable.tableSpec(35), useCaches: useCaches)
self.orderedItemListIndexTable = OrderedItemListIndexTable(valueBox: self.valueBox, table: OrderedItemListIndexTable.tableSpec(37), useCaches: useCaches)
self.orderedItemListTable = OrderedItemListTable(valueBox: self.valueBox, table: OrderedItemListTable.tableSpec(38), useCaches: useCaches, indexTable: self.orderedItemListIndexTable)
self.unorderedItemListTable = UnorderedItemListTable(valueBox: self.valueBox, table: UnorderedItemListTable.tableSpec(42), useCaches: useCaches)
self.noticeTable = NoticeTable(valueBox: self.valueBox, table: NoticeTable.tableSpec(43), useCaches: useCaches)
self.deviceContactImportInfoTable = DeviceContactImportInfoTable(valueBox: self.valueBox, table: DeviceContactImportInfoTable.tableSpec(54), useCaches: useCaches)
self.groupMessageStatsTable = GroupMessageStatsTable(valueBox: self.valueBox, table: GroupMessageStatsTable.tableSpec(58), useCaches: useCaches)
var tables: [Table] = []
tables.append(self.metadataTable)

View File

@ -5,7 +5,7 @@ import SwiftSignalKit
func postboxUpgrade_21to22(queue: Queue, basePath: String, valueBox: ValueBox, encryptionParameters: ValueBoxEncryptionParameters, progress: (Float) -> Void) -> String? {
postboxLog("Upgrade 21->22 started")
valueBox.begin()
let metadataTable = MetadataTable(valueBox: valueBox, table: MetadataTable.tableSpec(0))
let metadataTable = MetadataTable(valueBox: valueBox, table: MetadataTable.tableSpec(0), useCaches: false)
metadataTable.setUserVersion(22)
valueBox.commit()
return nil

View File

@ -163,6 +163,7 @@ public final class SqliteValueBox: ValueBox {
fileprivate let basePath: String
private let isTemporary: Bool
private let isReadOnly: Bool
private let useCaches: Bool
private let inMemory: Bool
private let encryptionParameters: ValueBoxEncryptionParameters?
private let databasePath: String
@ -201,10 +202,11 @@ public final class SqliteValueBox: ValueBox {
private let queue: Queue
public init?(basePath: String, queue: Queue, isTemporary: Bool, isReadOnly: Bool, encryptionParameters: ValueBoxEncryptionParameters?, upgradeProgress: (Float) -> Void, inMemory: Bool = false) {
public init?(basePath: String, queue: Queue, isTemporary: Bool, isReadOnly: Bool, useCaches: Bool, encryptionParameters: ValueBoxEncryptionParameters?, upgradeProgress: (Float) -> Void, inMemory: Bool = false) {
self.basePath = basePath
self.isTemporary = isTemporary
self.isReadOnly = isReadOnly
self.useCaches = useCaches
self.inMemory = inMemory
self.encryptionParameters = encryptionParameters
self.databasePath = basePath + "/db_sqlite"
@ -420,8 +422,11 @@ public final class SqliteValueBox: ValueBox {
}
postboxLog("Did set up encryption")
//database.execute("PRAGMA cache_size=-2097152")
if !self.useCaches {
resultCode = database.execute("PRAGMA cache_size=32")
assert(resultCode)
}
resultCode = database.execute("PRAGMA mmap_size=0")
assert(resultCode)
resultCode = database.execute("PRAGMA synchronous=NORMAL")

View File

@ -3,10 +3,12 @@ import Foundation
open class Table {
public final let valueBox: ValueBox
public final let table: ValueBoxTable
public final let useCaches: Bool
public init(valueBox: ValueBox, table: ValueBoxTable) {
public init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool) {
self.valueBox = valueBox
self.table = table
self.useCaches = useCaches
}
open func clearMemoryCache() {

View File

@ -26,10 +26,10 @@ final class TimestampBasedMessageAttributesTable: Table {
private let indexTable: TimestampBasedMessageAttributesIndexTable
init(valueBox: ValueBox, table: ValueBoxTable, indexTable: TimestampBasedMessageAttributesIndexTable) {
init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, indexTable: TimestampBasedMessageAttributesIndexTable) {
self.indexTable = indexTable
super.init(valueBox: valueBox, table: table)
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
}
private func key(tag: UInt16, timestamp: Int32, id: MessageId) -> ValueBoxKey {

View File

@ -33,6 +33,13 @@ final public class AdaptedPostboxDecoder {
}
func decode<T>(_ type: T.Type, from data: Data, contentType: ContentType) throws -> T where T : Decodable {
if type == AdaptedPostboxDecoder.RawObjectData.self {
if case .object = contentType {
return AdaptedPostboxDecoder.RawObjectData(data: data, typeHash: 0) as! T
} else {
preconditionFailure()
}
}
let decoder = _AdaptedPostboxDecoder(data: data, contentType: contentType)
return try T(from: decoder)
}

View File

@ -21,30 +21,30 @@ private func makeExclusiveKeychain(id: AccountRecordId, postbox: Postbox) -> Key
}
return dict
}
return Keychain(get: { key in
return Keychain(get: { [weak postbox] key in
let enabled = accountRecordToActiveKeychainId.with { dict -> Bool in
return dict[id] == keychainId
}
if enabled {
if enabled, let postbox = postbox {
return postbox.keychainEntryForKey(key)
} else {
Logger.shared.log("Keychain", "couldn't get \(key) — not current")
return nil
}
}, set: { (key, data) in
}, set: { [weak postbox] key, data in
let enabled = accountRecordToActiveKeychainId.with { dict -> Bool in
return dict[id] == keychainId
}
if enabled {
if enabled, let postbox = postbox {
postbox.setKeychainEntryForKey(key, value: data)
} else {
Logger.shared.log("Keychain", "couldn't set \(key) — not current")
}
}, remove: { key in
}, remove: { [weak postbox] key in
let enabled = accountRecordToActiveKeychainId.with { dict -> Bool in
return dict[id] == keychainId
}
if enabled {
if enabled, let postbox = postbox {
postbox.removeKeychainEntryForKey(key)
} else {
Logger.shared.log("Keychain", "couldn't remove \(key) — not current")
@ -162,85 +162,19 @@ public enum AccountResult {
case authorized(Account)
}
public enum AccountPreferenceEntriesResult {
case progress(Float)
case result(String, [ValueBoxKey: PreferencesEntry])
}
public func accountPreferenceEntries(rootPath: String, id: AccountRecordId, keys: Set<ValueBoxKey>, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<AccountPreferenceEntriesResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: true, useCopy: false)
return postbox
|> mapToSignal { value -> Signal<AccountPreferenceEntriesResult, NoError> in
switch value {
case let .upgrading(progress):
return .single(.progress(progress))
case let .postbox(postbox):
return postbox.transaction { transaction -> AccountPreferenceEntriesResult in
var result: [ValueBoxKey: PreferencesEntry] = [:]
for key in keys {
if let value = transaction.getPreferencesEntry(key: key) {
result[key] = value
}
}
return .result(path, result)
}
case .error:
return .single(.progress(0.0))
}
}
}
public enum AccountNoticeEntriesResult {
case progress(Float)
case result(String, [ValueBoxKey: NoticeEntry])
}
public func accountNoticeEntries(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<AccountNoticeEntriesResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: true, useCopy: false)
return postbox
|> mapToSignal { value -> Signal<AccountNoticeEntriesResult, NoError> in
switch value {
case let .upgrading(progress):
return .single(.progress(progress))
case let .postbox(postbox):
return postbox.transaction { transaction -> AccountNoticeEntriesResult in
return .result(path, transaction.getAllNoticeEntries())
}
case .error:
return .single(.progress(0.0))
}
}
}
public enum LegacyAccessChallengeDataResult {
case progress(Float)
case result(PostboxAccessChallengeData)
}
public func accountLegacyAccessChallengeData(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<LegacyAccessChallengeDataResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: true, useCopy: false)
return postbox
|> mapToSignal { value -> Signal<LegacyAccessChallengeDataResult, NoError> in
switch value {
case let .upgrading(progress):
return .single(.progress(progress))
case let .postbox(postbox):
return postbox.transaction { transaction -> LegacyAccessChallengeDataResult in
return .result(transaction.legacyGetAccessChallengeData())
}
case .error:
return .single(.progress(0.0))
}
}
}
public func accountWithId(accountManager: AccountManager<TelegramAccountManagerTypes>, networkArguments: NetworkInitializationArguments, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, supplementary: Bool, rootPath: String, beginWithTestingEnvironment: Bool, backupData: AccountBackupData?, auxiliaryMethods: AccountAuxiliaryMethods, shouldKeepAutoConnection: Bool = true) -> Signal<AccountResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: false, isReadOnly: false, useCopy: false)
let postbox = openPostbox(
basePath: path + "/postbox",
seedConfiguration: telegramPostboxSeedConfiguration,
encryptionParameters: encryptionParameters,
timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970),
isTemporary: false,
isReadOnly: false,
useCopy: false,
useCaches: !supplementary
)
return postbox
|> mapToSignal { result -> Signal<AccountResult, NoError> in
@ -251,7 +185,11 @@ public func accountWithId(accountManager: AccountManager<TelegramAccountManagerT
return .single(.upgrading(0.0))
case let .postbox(postbox):
return accountManager.transaction { transaction -> (LocalizationSettings?, ProxySettings?) in
return (transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self), transaction.getSharedData(SharedDataKeys.proxySettings)?.get(ProxySettings.self))
var localizationSettings: LocalizationSettings?
if !supplementary {
localizationSettings = transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self)
}
return (localizationSettings, transaction.getSharedData(SharedDataKeys.proxySettings)?.get(ProxySettings.self))
}
|> mapToSignal { localizationSettings, proxySettings -> Signal<AccountResult, NoError> in
return postbox.transaction { transaction -> (PostboxCoding?, LocalizationSettings?, ProxySettings?, NetworkSettings?) in
@ -740,22 +678,30 @@ public struct MasterNotificationKey: Codable {
}
public func masterNotificationsKey(account: Account, ignoreDisabled: Bool) -> Signal<MasterNotificationKey, NoError> {
return masterNotificationsKey(masterNotificationKeyValue: account.masterNotificationKey, postbox: account.postbox, ignoreDisabled: ignoreDisabled)
return masterNotificationsKey(masterNotificationKeyValue: account.masterNotificationKey, postbox: account.postbox, ignoreDisabled: ignoreDisabled, createIfNotExists: true)
|> map { value -> MasterNotificationKey in
return value!
}
}
private func masterNotificationsKey(masterNotificationKeyValue: Atomic<MasterNotificationKey?>, postbox: Postbox, ignoreDisabled: Bool) -> Signal<MasterNotificationKey, NoError> {
public func existingMasterNotificationsKey(postbox: Postbox) -> Signal<MasterNotificationKey?, NoError> {
let value = Atomic<MasterNotificationKey?>(value: nil)
return masterNotificationsKey(masterNotificationKeyValue: value, postbox: postbox, ignoreDisabled: true, createIfNotExists: false)
}
private func masterNotificationsKey(masterNotificationKeyValue: Atomic<MasterNotificationKey?>, postbox: Postbox, ignoreDisabled: Bool, createIfNotExists: Bool) -> Signal<MasterNotificationKey?, NoError> {
if let key = masterNotificationKeyValue.with({ $0 }) {
return .single(key)
}
return postbox.transaction(ignoreDisabled: ignoreDisabled, { transaction -> MasterNotificationKey in
return postbox.transaction(ignoreDisabled: ignoreDisabled, { transaction -> MasterNotificationKey? in
if let value = transaction.keychainEntryForKey("master-notification-secret"), !value.isEmpty {
let authKeyHash = sha1Digest(value)
let authKeyId = authKeyHash.subdata(in: authKeyHash.count - 8 ..< authKeyHash.count)
let keyData = MasterNotificationKey(id: authKeyId, data: value)
let _ = masterNotificationKeyValue.swap(keyData)
return keyData
} else {
} else if createIfNotExists {
var secretData = Data(count: 256)
let secretDataCount = secretData.count
if !secretData.withUnsafeMutableBytes({ rawBytes -> Bool in
@ -772,6 +718,8 @@ private func masterNotificationsKey(masterNotificationKeyValue: Atomic<MasterNot
let keyData = MasterNotificationKey(id: authKeyId, data: secretData)
let _ = masterNotificationKeyValue.swap(keyData)
return keyData
} else {
return nil
}
})
}
@ -818,8 +766,11 @@ public func decryptedNotificationPayload(key: MasterNotificationKey, data: Data)
}
public func decryptedNotificationPayload(account: Account, data: Data) -> Signal<Data?, NoError> {
return masterNotificationsKey(masterNotificationKeyValue: account.masterNotificationKey, postbox: account.postbox, ignoreDisabled: true)
return masterNotificationsKey(masterNotificationKeyValue: account.masterNotificationKey, postbox: account.postbox, ignoreDisabled: true, createIfNotExists: false)
|> map { secret -> Data? in
guard let secret = secret else {
return nil
}
return decryptedNotificationPayload(key: secret, data: data)
}
}
@ -969,12 +920,8 @@ public class Account {
let networkStateQueue = Queue()
let networkStateSignal = combineLatest(queue: networkStateQueue, self.stateManager.isUpdating, network.connectionStatus/*, delayNetworkStatus*/)
|> map { isUpdating, connectionStatus/*, delayNetworkStatus*/ -> AccountNetworkState in
/*if delayNetworkStatus {
return .online(proxy: nil)
}*/
let networkStateSignal = combineLatest(queue: networkStateQueue, self.stateManager.isUpdating, network.connectionStatus)
|> map { isUpdating, connectionStatus -> AccountNetworkState in
switch connectionStatus {
case .waitingForNetwork:
return .waitingForNetwork
@ -1076,7 +1023,10 @@ public class Account {
self.managedOperationsDisposable.add(managedApplyPendingMessageReactionsActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start())
self.managedOperationsDisposable.add(managedSynchronizeEmojiKeywordsOperations(postbox: self.postbox, network: self.network).start())
self.managedOperationsDisposable.add(managedApplyPendingScheduledMessagesActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start())
self.managedOperationsDisposable.add(managedChatListFilters(postbox: self.postbox, network: self.network, accountPeerId: self.peerId).start())
if !supplementary {
self.managedOperationsDisposable.add(managedChatListFilters(postbox: self.postbox, network: self.network, accountPeerId: self.peerId).start())
}
let importantBackgroundOperations: [Signal<AccountRunningImportantTasks, NoError>] = [
managedSynchronizeChatInputStateOperations(postbox: self.postbox, network: self.network) |> map { $0 ? AccountRunningImportantTasks.other : [] },
@ -1140,7 +1090,7 @@ public class Account {
self.managedOperationsDisposable.add(managedSynchronizeAppLogEventsOperations(postbox: self.postbox, network: self.network).start())
self.managedOperationsDisposable.add(managedNotificationSettingsBehaviors(postbox: self.postbox).start())
self.managedOperationsDisposable.add(managedThemesUpdates(accountManager: accountManager, postbox: self.postbox, network: self.network).start())
if !self.testingEnvironment {
if !self.testingEnvironment && !supplementary {
self.managedOperationsDisposable.add(managedChatThemesUpdates(accountManager: accountManager, network: self.network).start())
}
@ -1161,7 +1111,7 @@ public class Account {
})
}
let _ = masterNotificationsKey(masterNotificationKeyValue: self.masterNotificationKey, postbox: self.postbox, ignoreDisabled: false).start(next: { key in
let _ = masterNotificationsKey(masterNotificationKeyValue: self.masterNotificationKey, postbox: self.postbox, ignoreDisabled: false, createIfNotExists: true).start(next: { key in
let encoder = JSONEncoder()
if let data = try? encoder.encode(key) {
let _ = try? data.write(to: URL(fileURLWithPath: "\(basePath)/notificationsKey"))
@ -1301,3 +1251,95 @@ public func setupAccount(_ account: Account, fetchCachedResourceRepresentation:
account.pendingMessageManager.transformOutgoingMessageMedia = transformOutgoingMessageMedia
account.pendingUpdateMessageManager.transformOutgoingMessageMedia = transformOutgoingMessageMedia
}
public func standaloneStateManager(
accountManager: AccountManager<TelegramAccountManagerTypes>,
networkArguments: NetworkInitializationArguments,
id: AccountRecordId,
encryptionParameters: ValueBoxEncryptionParameters,
rootPath: String,
auxiliaryMethods: AccountAuxiliaryMethods
) -> Signal<AccountStateManager?, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(
basePath: path + "/postbox",
seedConfiguration: telegramPostboxSeedConfiguration,
encryptionParameters: encryptionParameters,
timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970),
isTemporary: false,
isReadOnly: false,
useCopy: false,
useCaches: false
)
return postbox
|> take(1)
|> mapToSignal { result -> Signal<AccountStateManager?, NoError> in
switch result {
case .upgrading:
return .single(nil)
case .error:
return .single(nil)
case let .postbox(postbox):
return accountManager.transaction { transaction -> (LocalizationSettings?, ProxySettings?) in
return (nil, transaction.getSharedData(SharedDataKeys.proxySettings)?.get(ProxySettings.self))
}
|> mapToSignal { localizationSettings, proxySettings -> Signal<AccountStateManager?, NoError> in
return postbox.transaction { transaction -> (PostboxCoding?, LocalizationSettings?, ProxySettings?, NetworkSettings?) in
let state = transaction.getState()
return (state, localizationSettings, proxySettings, transaction.getPreferencesEntry(key: PreferencesKeys.networkSettings)?.get(NetworkSettings.self))
}
|> mapToSignal { accountState, localizationSettings, proxySettings, networkSettings -> Signal<AccountStateManager?, NoError> in
let keychain = makeExclusiveKeychain(id: id, postbox: postbox)
if let accountState = accountState {
switch accountState {
case _ as UnauthorizedAccountState:
return .single(nil)
case let authorizedState as AuthorizedAccountState:
return postbox.transaction { transaction -> String? in
return (transaction.getPeer(authorizedState.peerId) as? TelegramUser)?.phone
}
|> mapToSignal { phoneNumber in
return initializedNetwork(
accountId: id,
arguments: networkArguments,
supplementary: true,
datacenterId: Int(authorizedState.masterDatacenterId),
keychain: keychain,
basePath: path,
testingEnvironment: authorizedState.isTestingEnvironment,
languageCode: localizationSettings?.primaryComponent.languageCode,
proxySettings: proxySettings,
networkSettings: networkSettings,
phoneNumber: phoneNumber
)
|> map { network -> AccountStateManager? in
return AccountStateManager(
accountPeerId: authorizedState.peerId,
accountManager: accountManager,
postbox: postbox,
network: network,
callSessionManager: nil,
addIsContactUpdates: { _ in
},
shouldKeepOnlinePresence: .single(false),
peerInputActivityManager: nil,
auxiliaryMethods: auxiliaryMethods
)
}
}
default:
assertionFailure("Unexpected accountState \(accountState)")
return .single(nil)
}
} else {
return .single(nil)
}
}
}
}
}
}

View File

@ -282,36 +282,6 @@ public func performAppGroupUpgrades(appGroupPath: String, rootPath: String) {
}
}
public final class TemporaryAccount {
public let id: AccountRecordId
public let basePath: String
public let postbox: Postbox
init(id: AccountRecordId, basePath: String, postbox: Postbox) {
self.id = id
self.basePath = basePath
self.postbox = postbox
}
}
public func temporaryAccount(manager: AccountManager<TelegramAccountManagerTypes>, rootPath: String, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<TemporaryAccount, NoError> {
return manager.allocatedTemporaryAccountId()
|> mapToSignal { id -> Signal<TemporaryAccount, NoError> in
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
return openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: false, isReadOnly: false, useCopy: false)
|> mapToSignal { result -> Signal<TemporaryAccount, NoError> in
switch result {
case .upgrading:
return .complete()
case .error:
return .complete()
case let .postbox(postbox):
return .single(TemporaryAccount(id: id, basePath: path, postbox: postbox))
}
}
}
}
public func currentAccount(allocateIfNotExists: Bool, networkArguments: NetworkInitializationArguments, supplementary: Bool, manager: AccountManager<TelegramAccountManagerTypes>, rootPath: String, auxiliaryMethods: AccountAuxiliaryMethods, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<AccountResult?, NoError> {
return manager.currentAccountRecord(allocateIfNotExists: allocateIfNotExists)
|> distinctUntilChanged(isEqual: { lhs, rhs in

View File

@ -423,16 +423,6 @@ public struct NetworkInitializationArguments {
private let cloudDataContext = Atomic<CloudDataContext?>(value: nil)
#endif
private final class SharedContextStore {
struct Key: Hashable {
var accountId: AccountRecordId
}
var contexts: [Key: MTContext] = [:]
}
private let sharedContexts = Atomic<SharedContextStore>(value: SharedContextStore())
func initializedNetwork(accountId: AccountRecordId, arguments: NetworkInitializationArguments, supplementary: Bool, datacenterId: Int, keychain: Keychain, basePath: String, testingEnvironment: Bool, languageCode: String?, proxySettings: ProxySettings?, networkSettings: NetworkSettings?, phoneNumber: String?) -> Signal<Network, NoError> {
return Signal { subscriber in
let queue = Queue()
@ -475,19 +465,7 @@ func initializedNetwork(accountId: AccountRecordId, arguments: NetworkInitializa
let useTempAuthKeys: Bool = true
var contextValue: MTContext?
sharedContexts.with { store in
let key = SharedContextStore.Key(accountId: accountId)
let context: MTContext
context = MTContext(serialization: serialization, encryptionProvider: arguments.encryptionProvider, apiEnvironment: apiEnvironment, isTestingEnvironment: testingEnvironment, useTempAuthKeys: useTempAuthKeys)
store.contexts[key] = context
contextValue = context
}
let context = contextValue!
let context = MTContext(serialization: serialization, encryptionProvider: arguments.encryptionProvider, apiEnvironment: apiEnvironment, isTestingEnvironment: testingEnvironment, useTempAuthKeys: useTempAuthKeys)
let seedAddressList: [Int: [String]]
@ -539,10 +517,6 @@ func initializedNetwork(accountId: AccountRecordId, arguments: NetworkInitializa
#endif
context.setDiscoverBackupAddressListSignal(MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber))
#if DEBUG
//let _ = MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber).start(next: nil)
#endif
let mtProto = MTProto(context: context, datacenterId: datacenterId, usageCalculationInfo: usageCalculationInfo(basePath: basePath, category: nil), requiredAuthToken: nil, authTokenMasterDatacenterId: 0)!
mtProto.useTempAuthKeys = context.useTempAuthKeys
mtProto.checkForProxyConnectionIssues = true

View File

@ -52,15 +52,15 @@ public enum DeletedMessageId: Hashable {
public final class AccountStateManager {
private let queue = Queue()
private let accountPeerId: PeerId
public let accountPeerId: PeerId
private let accountManager: AccountManager<TelegramAccountManagerTypes>
private let postbox: Postbox
private let network: Network
private let callSessionManager: CallSessionManager
public let postbox: Postbox
public let network: Network
private let callSessionManager: CallSessionManager?
private let addIsContactUpdates: ([(PeerId, Bool)]) -> Void
private let shouldKeepOnlinePresence: Signal<Bool, NoError>
private let peerInputActivityManager: PeerInputActivityManager
private let peerInputActivityManager: PeerInputActivityManager?
let auxiliaryMethods: AccountAuxiliaryMethods
var transformOutgoingMessageMedia: TransformOutgoingMessageMedia?
@ -166,7 +166,7 @@ public final class AccountStateManager {
private let appliedQtsPromise = Promise<Int32?>(nil)
private let appliedQtsDisposable = MetaDisposable()
init(accountPeerId: PeerId, accountManager: AccountManager<TelegramAccountManagerTypes>, postbox: Postbox, network: Network, callSessionManager: CallSessionManager, addIsContactUpdates: @escaping ([(PeerId, Bool)]) -> Void, shouldKeepOnlinePresence: Signal<Bool, NoError>, peerInputActivityManager: PeerInputActivityManager, auxiliaryMethods: AccountAuxiliaryMethods) {
init(accountPeerId: PeerId, accountManager: AccountManager<TelegramAccountManagerTypes>, postbox: Postbox, network: Network, callSessionManager: CallSessionManager?, addIsContactUpdates: @escaping ([(PeerId, Bool)]) -> Void, shouldKeepOnlinePresence: Signal<Bool, NoError>, peerInputActivityManager: PeerInputActivityManager?, auxiliaryMethods: AccountAuxiliaryMethods) {
self.accountPeerId = accountPeerId
self.accountManager = accountManager
self.postbox = postbox
@ -183,9 +183,14 @@ public final class AccountStateManager {
self.operationDisposable.dispose()
self.appliedMaxMessageIdDisposable.dispose()
self.appliedQtsDisposable.dispose()
var postbox: Postbox? = self.postbox
postbox?.queue.async {
postbox = nil
}
}
func reset() {
public func reset() {
self.queue.async {
if self.updateService == nil {
self.updateService = UpdateMessageService(peerId: self.accountPeerId)
@ -641,7 +646,7 @@ public final class AccountStateManager {
let topOperation = strongSelf.operations.removeFirst()
if case .processEvents(operationId, _) = topOperation.content {
if !events.updatedTypingActivities.isEmpty {
strongSelf.peerInputActivityManager.transaction { manager in
strongSelf.peerInputActivityManager?.transaction { manager in
for (chatPeerId, peerActivities) in events.updatedTypingActivities {
for (peerId, activity) in peerActivities {
if let activity = activity {
@ -661,12 +666,12 @@ public final class AccountStateManager {
}
if !events.updatedCalls.isEmpty {
for call in events.updatedCalls {
strongSelf.callSessionManager.updateSession(call, completion: { _ in })
strongSelf.callSessionManager?.updateSession(call, completion: { _ in })
}
}
if !events.addedCallSignalingData.isEmpty {
for (id, data) in events.addedCallSignalingData {
strongSelf.callSessionManager.addCallSignalingData(id: id, data: data)
strongSelf.callSessionManager?.addCallSignalingData(id: id, data: data)
}
}
if !events.updatedGroupCallParticipants.isEmpty {
@ -1046,9 +1051,13 @@ public final class AccountStateManager {
for update in updates {
switch update {
case let .updatePhoneCall(phoneCall):
self.callSessionManager.updateSession(phoneCall, completion: { result in
completion(result)
})
if let callSessionManager = self.callSessionManager {
callSessionManager.updateSession(phoneCall, completion: { result in
completion(result)
})
} else {
completion(nil)
}
return
default:
break

View File

@ -97,9 +97,9 @@ public enum AccountTransactionError {
case couldNotOpen
}
public func accountTransaction<T>(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, isReadOnly: Bool, useCopy: Bool = false, transaction: @escaping (Postbox, Transaction) -> T) -> Signal<T, AccountTransactionError> {
public func accountTransaction<T>(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, isReadOnly: Bool, useCopy: Bool = false, useCaches: Bool = true, transaction: @escaping (Postbox, Transaction) -> T) -> Signal<T, AccountTransactionError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: isReadOnly, useCopy: useCopy)
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: isReadOnly, useCopy: useCopy, useCaches: useCaches)
return postbox
|> castError(AccountTransactionError.self)
|> mapToSignal { value -> Signal<T, AccountTransactionError> in

View File

@ -677,7 +677,7 @@ final class SharedApplicationContext {
})
let accountManagerSignal = Signal<AccountManager<TelegramAccountManagerTypes>, NoError> { subscriber in
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: false, isReadOnly: false)
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: false, isReadOnly: false, useCaches: true)
return (upgradedAccounts(accountManager: accountManager, rootPath: rootPath, encryptionParameters: encryptionParameters)
|> deliverOnMainQueue).start(next: { progress in
if self.dataImportSplash == nil {
@ -1489,6 +1489,10 @@ final class SharedApplicationContext {
}
public func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {
if "".isEmpty {
return;
}
if #available(iOS 9.0, *) {
/*guard var encryptedPayload = payload.dictionaryPayload["p"] as? String else {
return

View File

@ -94,7 +94,7 @@ public final class NotificationViewControllerImpl {
if sharedAccountContext == nil {
initializeAccountManagement()
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false)
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false, useCaches: false)
var initialPresentationDataAndSettings: InitialPresentationDataAndSettings?
let semaphore = DispatchSemaphore(value: 0)

View File

@ -624,10 +624,10 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
game = value
} else if queryItem.name == "post" {
post = value
} else if queryItem.name == "voicechat" {
} else if queryItem.name == "voicechat" || queryItem.name == "videochat" || queryItem.name == "livestream" {
voiceChat = value
}
} else if queryItem.name == "voicechat" {
} else if queryItem.name == "voicechat" || queryItem.name == "videochat" || queryItem.name == "livestream" {
voiceChat = ""
}
}

View File

@ -205,7 +205,7 @@ public class ShareRootControllerImpl {
let internalContext: InternalContext
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false)
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false, useCaches: false)
if let globalInternalContext = globalInternalContext {
internalContext = globalInternalContext

View File

@ -111,204 +111,11 @@ public func upgradedAccounts(accountManager: AccountManager<TelegramAccountManag
return (transaction.getVersion(), transaction.getCurrent()?.0)
}
|> mapToSignal { version, currentId -> Signal<Float, NoError> in
guard let version = version else {
return accountManager.transaction { transaction -> Void in
transaction.setVersion(4)
}
|> ignoreValues
|> mapToSignal { _ -> Signal<Float, NoError> in
}
return accountManager.transaction { transaction -> Void in
transaction.setVersion(4)
}
var signal: Signal<Float, NoError> = .complete()
if version < 1 {
if let currentId = currentId {
let upgradePreferences = accountPreferenceEntries(rootPath: rootPath, id: currentId, keys: Set(preferencesKeyMapping.keys.map({ $0.key }) + applicationSpecificPreferencesKeyMapping.keys.map({ $0.key })), encryptionParameters: encryptionParameters)
|> mapToSignal { result -> Signal<Float, NoError> in
switch result {
case let .progress(progress):
return .single(progress)
case let .result(path, values):
return accountManager.transaction { transaction -> Void in
for (key, value) in values {
var upgradedKey: ValueBoxKey?
for (k, v) in preferencesKeyMapping {
if k.key == key {
upgradedKey = v.key
break
}
}
for (k, v) in applicationSpecificPreferencesKeyMapping {
if k.key == key {
upgradedKey = v.key
break
}
}
if let upgradedKey = upgradedKey {
transaction.updateSharedData(upgradedKey, { _ in
return upgradedSharedDataValue(value)
})
}
}
if let value = values[LegacyApplicationSpecificPreferencesKeyValues.presentationThemeSettings.key]?.get(PresentationThemeSettings.self) {
let mediaBox = MediaBox(basePath: path + "/postbox/media")
let wallpapers = Array(value.themeSpecificChatWallpapers.values)
for wallpaper in wallpapers {
switch wallpaper {
case let .file(file):
if let path = mediaBox.completedResourcePath(file.file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
accountManager.mediaBox.storeResourceData(file.file.resource.id, data: data)
let _ = accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: true, fetch: true).start()
if wallpaper.isPattern {
} else {
if file.settings.blur {
let _ = accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start()
}
}
}
case let .image(representations, _):
for representation in representations {
let resource = representation.resource
if let path = mediaBox.completedResourcePath(resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
accountManager.mediaBox.storeResourceData(resource.id, data: data)
let _ = mediaBox.cachedResourceRepresentation(resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: true, fetch: true).start()
}
}
default:
break
}
}
}
transaction.setVersion(1)
}
|> mapToSignal { _ -> Signal<Float, NoError> in
return .complete()
}
}
}
signal = signal |> then(upgradePreferences)
} else {
let upgradePreferences = accountManager.transaction { transaction -> Void in
transaction.setVersion(1)
}
|> mapToSignal { _ -> Signal<Float, NoError> in
return .complete()
}
signal = signal |> then(upgradePreferences)
|> ignoreValues
|> mapToSignal { _ -> Signal<Float, NoError> in
}
}
if version < 2 {
if let currentId = currentId {
let upgradeNotices = accountNoticeEntries(rootPath: rootPath, id: currentId, encryptionParameters: encryptionParameters)
|> mapToSignal { result -> Signal<Float, NoError> in
switch result {
case let .progress(progress):
return .single(progress)
case let .result(_, values):
return accountManager.transaction { transaction -> Void in
for (key, value) in values {
transaction.setNotice(NoticeEntryKey(namespace: ValueBoxKey(length: 0), key: key), value)
}
transaction.setVersion(2)
}
|> mapToSignal { _ -> Signal<Float, NoError> in
return .complete()
}
}
}
signal = signal |> then(upgradeNotices)
} else {
let upgradeNotices = accountManager.transaction { transaction -> Void in
transaction.setVersion(2)
}
|> mapToSignal { _ -> Signal<Float, NoError> in
return .complete()
}
signal = signal |> then(upgradeNotices)
}
let upgradeSortOrder = accountManager.transaction { transaction -> Void in
var index: Int32 = 0
for record in transaction.getRecords() {
transaction.updateRecord(record.id, { _ in
return AccountRecord(id: record.id, attributes: record.attributes + [.sortOrder(AccountSortOrderAttribute(order: index))], temporarySessionId: record.temporarySessionId)
})
index += 1
}
}
|> mapToSignal { _ -> Signal<Float, NoError> in
return .complete()
}
signal = signal |> then(upgradeSortOrder)
}
if version < 3 {
if let currentId = currentId {
let upgradeAccessChallengeData = accountLegacyAccessChallengeData(rootPath: rootPath, id: currentId, encryptionParameters: encryptionParameters)
|> mapToSignal { result -> Signal<Float, NoError> in
switch result {
case let .progress(progress):
return .single(progress)
case let .result(accessChallengeData):
return accountManager.transaction { transaction -> Void in
if case .none = transaction.getAccessChallengeData() {
transaction.setAccessChallengeData(accessChallengeData)
}
transaction.setVersion(3)
}
|> mapToSignal { _ -> Signal<Float, NoError> in
return .complete()
}
}
}
signal = signal |> then(upgradeAccessChallengeData)
} else {
let upgradeAccessChallengeData = accountManager.transaction { transaction -> Void in
transaction.setVersion(3)
}
|> mapToSignal { _ -> Signal<Float, NoError> in
return .complete()
}
signal = signal |> then(upgradeAccessChallengeData)
}
}
if version < 4 {
let updatedContactSynchronizationSettings = accountManager.transaction { transaction -> (ContactSynchronizationSettings, [AccountRecordId]) in
return (transaction.getSharedData(ApplicationSpecificSharedDataKeys.contactSynchronizationSettings)?.get(ContactSynchronizationSettings.self) ?? ContactSynchronizationSettings.defaultSettings, transaction.getRecords().map({ $0.id }))
}
|> mapToSignal { globalSettings, ids -> Signal<Never, NoError> in
var importSignal: Signal<Never, NoError> = .complete()
for id in ids {
let importInfoAccounttSignal = accountTransaction(rootPath: rootPath, id: id, encryptionParameters: encryptionParameters, isReadOnly: false, transaction: { _, transaction -> Void in
transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in
var settings = current?.get(ContactsSettings.self) ?? ContactsSettings.defaultSettings
settings.synchronizeContacts = globalSettings._legacySynchronizeDeviceContacts
return PreferencesEntry(settings)
})
})
|> ignoreValues
|> `catch` { _ -> Signal<Never, NoError> in
return .complete()
}
importSignal = importSignal |> then(importInfoAccounttSignal)
}
return importSignal
}
let applyVersion = accountManager.transaction { transaction -> Void in
transaction.setVersion(4)
}
|> ignoreValues
signal = signal |> then(
(updatedContactSynchronizationSettings
|> then(
applyVersion
)) |> mapToSignal { _ -> Signal<Float, NoError> in
}
)
}
return signal
}
}

View File

@ -136,10 +136,10 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
return .peerName(peerName, .groupBotStart(value))
} else if queryItem.name == "game" {
return nil
} else if queryItem.name == "voicechat" {
} else if queryItem.name == "voicechat" || queryItem.name == "videochat" || queryItem.name == "livestream" {
return .peerName(peerName, .voiceChat(value))
}
} else if queryItem.name == "voicechat" {
} else if queryItem.name == "voicechat" || queryItem.name == "videochat" || queryItem.name == "livestream" {
return .peerName(peerName, .voiceChat(nil))
}
}