import PromiseKit // Some important notes about YapDatabase: // // • Connections are thread-safe. // • Executing a write transaction from within a write transaction is NOT allowed. @objc(LKStorage) public final class Storage : NSObject, SessionMessagingKitStorageProtocol, SessionProtocolKitStorageProtocol, SessionSnodeKitStorageProtocol { public static let serialQueue = DispatchQueue(label: "Storage.serialQueue", qos: .userInitiated) private static var owsStorage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } @objc public static let shared = Storage() // MARK: Reading // Some important points regarding reading from the database: // // • Background threads should use `OWSPrimaryStorage`'s `dbReadConnection`, whereas the main thread should use `OWSPrimaryStorage`'s `uiDatabaseConnection` (see the `YapDatabaseConnectionPool` documentation for more information). // • Multiple read transactions can safely be executed at the same time. @objc(readWithBlock:) public static func read(with block: @escaping (YapDatabaseReadTransaction) -> Void) { owsStorage.dbReadConnection.read(block) } // MARK: Writing // Some important points regarding writing to the database: // // • There can only be a single write transaction per database at any one time, so all write transactions must use `OWSPrimaryStorage`'s `dbReadWriteConnection`. // • Executing a write transaction from within a write transaction causes a deadlock and must be avoided. @discardableResult @objc(writeWithBlock:) public static func objc_write(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) -> AnyPromise { return AnyPromise.from(write(with: block) { }) } @discardableResult public static func write(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) -> Promise { return write(with: block) { } } @discardableResult @objc(writeWithBlock:completion:) public static func objc_write(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void, completion: @escaping () -> Void) -> AnyPromise { return AnyPromise.from(write(with: block, completion: completion)) } @discardableResult public static func write(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void, completion: @escaping () -> Void) -> Promise { let (promise, seal) = Promise.pending() serialQueue.async { owsStorage.dbReadWriteConnection.readWrite { transaction in transaction.addCompletionQueue(DispatchQueue.main, completionBlock: completion) block(transaction) } seal.fulfill(()) } return promise } /// Blocks the calling thread until the write has finished. @objc(writeSyncWithBlock:) public static func writeSync(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) { try! write(with: block, completion: { }).wait() // The promise returned by write(with:completion:) never rejects } }