From b96742a0d40b6a11dd591e3d858750ee26108a78 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 16 Jun 2017 12:15:42 +0300 Subject: [PATCH] no message --- Postbox.xcodeproj/project.pbxproj | 20 ++++--- Postbox/ChatListIndexTable.swift | 69 +++++++++++++++++++---- Postbox/Database.swift | 8 ++- Postbox/PeerNameIndexRepresentation.swift | 40 +++++++++++-- Postbox/PeerNameIndexTable.swift | 10 +++- Postbox/Postbox.swift | 44 ++++++++++++--- Postbox/SqliteValueBox.swift | 6 +- 7 files changed, 158 insertions(+), 39 deletions(-) diff --git a/Postbox.xcodeproj/project.pbxproj b/Postbox.xcodeproj/project.pbxproj index d918e00b64..6a95e318d4 100644 --- a/Postbox.xcodeproj/project.pbxproj +++ b/Postbox.xcodeproj/project.pbxproj @@ -1267,10 +1267,11 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_CFLAGS = ( - "-DSQLITE_TEMP_STORE=2", "-DSQLITE_HAS_CODEC=1", "-DSQLCIPHER_CRYPTO_CC=1", - "-DSQLITE_ENABLE_FTS3", + "-DSQLITE_OMIT_DEPRECATED", + "-DSQLITE_ENABLE_FTS5", + "-DSQLITE_DEFAULT_MEMSTATUS=0", ); PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1394,10 +1395,11 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_CFLAGS = ( - "-DSQLITE_TEMP_STORE=2", "-DSQLITE_HAS_CODEC=1", "-DSQLCIPHER_CRYPTO_CC=1", - "-DSQLITE_ENABLE_FTS3", + "-DSQLITE_OMIT_DEPRECATED", + "-DSQLITE_ENABLE_FTS5", + "-DSQLITE_DEFAULT_MEMSTATUS=0", ); PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1642,10 +1644,11 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_CFLAGS = ( - "-DSQLITE_TEMP_STORE=2", "-DSQLITE_HAS_CODEC=1", "-DSQLCIPHER_CRYPTO_CC=1", - "-DSQLITE_ENABLE_FTS3", + "-DSQLITE_OMIT_DEPRECATED", + "-DSQLITE_ENABLE_FTS5", + "-DSQLITE_DEFAULT_MEMSTATUS=0", ); OTHER_SWIFT_FLAGS = "-DDEBUG"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; @@ -1675,10 +1678,11 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_CFLAGS = ( - "-DSQLITE_TEMP_STORE=2", "-DSQLITE_HAS_CODEC=1", "-DSQLCIPHER_CRYPTO_CC=1", - "-DSQLITE_ENABLE_FTS3", + "-DSQLITE_OMIT_DEPRECATED", + "-DSQLITE_ENABLE_FTS5", + "-DSQLITE_DEFAULT_MEMSTATUS=0", ); PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/Postbox/ChatListIndexTable.swift b/Postbox/ChatListIndexTable.swift index 83495c2d5e..57ce1ea40e 100644 --- a/Postbox/ChatListIndexTable.swift +++ b/Postbox/ChatListIndexTable.swift @@ -3,6 +3,7 @@ import Foundation struct ChatListInclusionIndex { let topMessageIndex: MessageIndex? let inclusion: PeerChatListInclusion + var tags: [UInt16]? func includedIndex(peerId: PeerId) -> ChatListIndex? { switch inclusion { @@ -32,6 +33,17 @@ struct ChatListInclusionIndex { } } +private struct ChatListIndexFlags: OptionSet { + var rawValue: Int8 + + init(rawValue: Int8) { + self.rawValue = rawValue + } + + static let hasIndex = ChatListIndexFlags(rawValue: 1 << 0) + static let hasTags = ChatListIndexFlags(rawValue: 1 << 1) +} + final class ChatListIndexTable: Table { static func tableSpec(_ id: Int32) -> ValueBoxTable { return ValueBoxTable(id: id, keyType: .int64) @@ -66,7 +78,7 @@ final class ChatListIndexTable: Table { if self.updatedPreviousCachedIndices[peerId] == nil { self.updatedPreviousCachedIndices[peerId] = current } - let updated = ChatListInclusionIndex(topMessageIndex: index, inclusion: current.inclusion) + let updated = ChatListInclusionIndex(topMessageIndex: index, inclusion: current.inclusion, tags: current.tags) self.cachedIndices[peerId] = updated return updated } @@ -76,7 +88,7 @@ final class ChatListIndexTable: Table { if self.updatedPreviousCachedIndices[peerId] == nil { self.updatedPreviousCachedIndices[peerId] = current } - let updated = ChatListInclusionIndex(topMessageIndex: current.topMessageIndex, inclusion: inclusion) + let updated = ChatListInclusionIndex(topMessageIndex: current.topMessageIndex, inclusion: inclusion, tags: current.tags) self.cachedIndices[peerId] = updated return updated } @@ -88,9 +100,11 @@ final class ChatListIndexTable: Table { if let value = self.valueBox.get(self.table, key: self.key(peerId)) { let topMessageIndex: MessageIndex? - var hasIndex: Int8 = 0 - value.read(&hasIndex, offset: 0, length: 1) - if hasIndex != 0 { + var flagsValue: Int8 = 0 + value.read(&flagsValue, offset: 0, length: 1) + let flags = ChatListIndexFlags(rawValue: flagsValue) + + if flags.contains(.hasIndex) { var idNamespace: Int32 = 0 var idId: Int32 = 0 var idTimestamp: Int32 = 0 @@ -131,11 +145,24 @@ final class ChatListIndexTable: Table { preconditionFailure() } - let inclusionIndex = ChatListInclusionIndex(topMessageIndex: topMessageIndex, inclusion: inclusion) + var tags: [UInt16]? + if flags.contains(.hasTags) { + var count: UInt16 = 0 + value.read(&count, offset: 0, length: 2) + var resultTags: [UInt16] = [] + for _ in 0 ..< Int(count) { + var tag: UInt16 = 0 + value.read(&tag, offset: 0, length: 2) + resultTags.append(tag) + } + tags = resultTags + } + + let inclusionIndex = ChatListInclusionIndex(topMessageIndex: topMessageIndex, inclusion: inclusion, tags: tags) self.cachedIndices[peerId] = inclusionIndex return inclusionIndex } else { - return ChatListInclusionIndex(topMessageIndex: nil, inclusion: .notSpecified) + return ChatListInclusionIndex(topMessageIndex: nil, inclusion: .notSpecified, tags: nil) } } } @@ -162,18 +189,26 @@ final class ChatListIndexTable: Table { let writeBuffer = WriteBuffer() + var flags: ChatListIndexFlags = [] + + if index.topMessageIndex != nil { + flags.insert(.hasIndex) + } + + if index.tags != nil { + flags.insert(.hasTags) + } + + var flagsValue = flags.rawValue + writeBuffer.write(&flagsValue, offset: 0, length: 1) + if let topMessageIndex = index.topMessageIndex { - var hasIndex: Int8 = 1 - writeBuffer.write(&hasIndex, offset: 0, length: 1) var idNamespace: Int32 = topMessageIndex.id.namespace var idId: Int32 = topMessageIndex.id.id var idTimestamp: Int32 = topMessageIndex.timestamp writeBuffer.write(&idNamespace, offset: 0, length: 4) writeBuffer.write(&idId, offset: 0, length: 4) writeBuffer.write(&idTimestamp, offset: 0, length: 4) - } else { - var hasIndex: Int8 = 0 - writeBuffer.write(&hasIndex, offset: 0, length: 1) } switch index.inclusion { @@ -205,6 +240,16 @@ final class ChatListIndexTable: Table { } } + if let tags = index.tags { + var count = UInt16(tags.count) + writeBuffer.write(&count, offset: 0, length: 2) + + for tag in tags { + var tagValue: UInt16 = tag + writeBuffer.write(&tagValue, offset: 0, length: 2) + } + } + withExtendedLifetime(writeBuffer, { self.valueBox.set(self.table, key: self.key(peerId), value: writeBuffer.readBufferNoCopy()) }) diff --git a/Postbox/Database.swift b/Postbox/Database.swift index 1712061b6d..fb557e8c4e 100644 --- a/Postbox/Database.swift +++ b/Postbox/Database.swift @@ -106,7 +106,13 @@ public final class Database { /// /// - parameter SQL: A batch of zero or more semicolon-separated SQL statements. public func execute(_ SQL: String) -> Bool { - return sqlite3_exec(self.handle, SQL, nil, nil, nil) == SQLITE_OK + let res = sqlite3_exec(self.handle, SQL, nil, nil, nil) + if res == SQLITE_OK { + return true + } else { + print("SQL error \(res) on SQL") + return false + } } } diff --git a/Postbox/PeerNameIndexRepresentation.swift b/Postbox/PeerNameIndexRepresentation.swift index fd6182f0d7..1974c29db3 100644 --- a/Postbox/PeerNameIndexRepresentation.swift +++ b/Postbox/PeerNameIndexRepresentation.swift @@ -2,7 +2,7 @@ import Foundation public enum PeerIndexNameRepresentation: Equatable { case title(title: String, addressName: String?) - case personName(first: String, last: String, addressName: String?) + case personName(first: String, last: String, addressName: String?, phoneNumber: String?) public static func ==(lhs: PeerIndexNameRepresentation, rhs: PeerIndexNameRepresentation) -> Bool { switch lhs { @@ -12,14 +12,41 @@ public enum PeerIndexNameRepresentation: Equatable { } else { return false } - case let .personName(lhsFirst, lhsLast, lhsAddressName): - if case let .personName(rhsFirst, rhsLast, rhsAddressName) = rhs, lhsFirst == rhsFirst, lhsLast == rhsLast, lhsAddressName == rhsAddressName { + case let .personName(lhsFirst, lhsLast, lhsAddressName, lhsPhoneNumber): + if case let .personName(rhsFirst, rhsLast, rhsAddressName, rhsPhoneNumber) = rhs, lhsFirst == rhsFirst, lhsLast == rhsLast, lhsAddressName == rhsAddressName, lhsPhoneNumber == rhsPhoneNumber { return true } else { return false } } } + + public var isEmpty: Bool { + switch self { + case let .title(title, addressName): + if !title.isEmpty { + return false + } + if let addressName = addressName, !addressName.isEmpty { + return false + } + return true + case let .personName(first, last, addressName, phoneNumber): + if !first.isEmpty { + return false + } + if !last.isEmpty { + return false + } + if let addressName = addressName, !addressName.isEmpty { + return false + } + if let phoneNumber = phoneNumber, !phoneNumber.isEmpty { + return false + } + return true + } + } } public enum PeerNameIndex { @@ -32,7 +59,7 @@ extension PeerIndexNameRepresentation { switch self { case let .title(title, _): return title - case let .personName(first, last, _): + case let .personName(first, last, _, _): switch index { case .firstNameFirst: return first + last @@ -68,12 +95,15 @@ extension PeerIndexNameRepresentation { tokens.append(contentsOf: stringIndexTokens(addressName, transliteration: .none)) } return tokens - case let .personName(first, last, addressName): + case let .personName(first, last, addressName, phoneNumber): var tokens: [ValueBoxKey] = stringIndexTokens(first, transliteration: .combined) tokens.append(contentsOf: stringIndexTokens(last, transliteration: .combined)) if let addressName = addressName { tokens.append(contentsOf: stringIndexTokens(addressName, transliteration: .none)) } + if let phoneNumber = phoneNumber { + tokens.append(contentsOf: stringIndexTokens(phoneNumber, transliteration: .none)) + } return tokens } } diff --git a/Postbox/PeerNameIndexTable.swift b/Postbox/PeerNameIndexTable.swift index 8baaceebfa..69a1feef4c 100644 --- a/Postbox/PeerNameIndexTable.swift +++ b/Postbox/PeerNameIndexTable.swift @@ -213,7 +213,15 @@ final class PeerNameIndexTable: Table { updatedTokens = updatedName.indexTokens } else { if let peer = self.peerTable.get(peerId) { - updatedTokens = peer.indexName.indexTokens + if let associatedPeerId = peer.associatedPeerId { + if let associatedPeer = self.peerTable.get(associatedPeerId) { + updatedTokens = associatedPeer.indexName.indexTokens + } else { + updatedTokens = [] + } + } else { + updatedTokens = peer.indexName.indexTokens + } } else { //assertionFailure() updatedTokens = [] diff --git a/Postbox/Postbox.swift b/Postbox/Postbox.swift index 769b40d3de..09e00aaf9d 100644 --- a/Postbox/Postbox.swift +++ b/Postbox/Postbox.swift @@ -1351,8 +1351,23 @@ public final class Postbox { if let updatedPeer = update(currentPeer, peer) { self.peerTable.set(updatedPeer) self.currentUpdatedPeers[updatedPeer.id] = updatedPeer - if currentPeer?.indexName != updatedPeer.indexName { - self.peerNameIndexTable.markPeerNameUpdated(peerId: peer.id, name: updatedPeer.indexName) + var previousIndexNameWasEmpty = true + + if let currentPeer = currentPeer { + if !currentPeer.indexName.isEmpty { + previousIndexNameWasEmpty = false + } + } + + let indexNameIsEmpty = updatedPeer.indexName.isEmpty + + if !previousIndexNameWasEmpty || !indexNameIsEmpty { + if currentPeer?.indexName != updatedPeer.indexName { + self.peerNameIndexTable.markPeerNameUpdated(peerId: peer.id, name: updatedPeer.indexName) + for reverseAssociatedPeerId in self.reverseAssociatedPeerTable.get(peerId: peer.id) { + self.peerNameIndexTable.markPeerNameUpdated(peerId: reverseAssociatedPeerId, name: updatedPeer.indexName) + } + } } } } @@ -1795,30 +1810,41 @@ public final class Postbox { } |> switchToLatest } - public func searchPeers(query: String) -> Signal<[Peer], NoError> { - return self.modify { modifier -> Signal<[Peer], NoError> in + public func searchPeers(query: String) -> Signal<[RenderedPeer], NoError> { + return self.modify { modifier -> Signal<[RenderedPeer], NoError> in var peerIds = Set() - var chatPeers: [Peer] = [] + var chatPeers: [RenderedPeer] = [] let (chatPeerIds, contactPeerIds) = self.peerNameIndexTable.matchingPeerIds(tokens: (regular: stringIndexTokens(query, transliteration: .none), transliterated: stringIndexTokens(query, transliteration: .transliterated)), categories: [.chats, .contacts], chatListIndexTable: self.chatListIndexTable, contactTable: self.contactsTable, reverseAssociatedPeerTable: self.reverseAssociatedPeerTable) for peerId in chatPeerIds { if let peer = self.peerTable.get(peerId) { - chatPeers.append(peer) + var peers = SimpleDictionary() + peers[peer.id] = peer + if let associatedPeerId = peer.associatedPeerId { + if let associatedPeer = self.peerTable.get(associatedPeerId) { + peers[associatedPeer.id] = associatedPeer + } + } + chatPeers.append(RenderedPeer(peerId: peer.id, peers: peers)) peerIds.insert(peerId) } } - var contactPeers: [Peer] = [] + var contactPeers: [RenderedPeer] = [] for peerId in contactPeerIds { if !peerIds.contains(peerId) { if let peer = self.peerTable.get(peerId) { - contactPeers.append(peer) + var peers = SimpleDictionary() + peers[peer.id] = peer + contactPeers.append(RenderedPeer(peerId: peer.id, peers: peers)) } } } - contactPeers.sort(by: { $0.indexName.indexName(.lastNameFirst) < $1.indexName.indexName(.lastNameFirst) }) + contactPeers.sort(by: { lhs, rhs in + lhs.peers[lhs.peerId]!.indexName.indexName(.lastNameFirst) < rhs.peers[rhs.peerId]!.indexName.indexName(.lastNameFirst) + }) return .single(chatPeers + contactPeers) } |> switchToLatest } diff --git a/Postbox/SqliteValueBox.swift b/Postbox/SqliteValueBox.swift index fac054801e..4551e289d2 100644 --- a/Postbox/SqliteValueBox.swift +++ b/Postbox/SqliteValueBox.swift @@ -149,7 +149,7 @@ final class SqliteValueBox: ValueBox { //database = Database(path)! } - sqlite3_busy_timeout(database.handle, 10000000) + sqlite3_busy_timeout(database.handle, 1000 * 10000) var resultCode: Bool @@ -158,9 +158,9 @@ final class SqliteValueBox: ValueBox { assert(resultCode) resultCode = database.execute("PRAGMA synchronous=NORMAL") assert(resultCode) - //database.execute("PRAGMA temp_store=MEMORY") - resultCode = database.execute("PRAGMA wal_autocheckpoint=500") + resultCode = database.execute("PRAGMA temp_store=MEMORY") assert(resultCode) + //resultCode = database.execute("PRAGMA wal_autocheckpoint=500") //database.execute("PRAGMA journal_size_limit=1536") /*var statement: OpaquePointer? = nil