Keep track of last message & last deletion server IDs

This commit is contained in:
nielsandriesse 2021-03-24 12:07:02 +11:00
parent 1d65f717b5
commit a5f831fd6c
3 changed files with 132 additions and 35 deletions

View File

@ -121,44 +121,56 @@ extension Storage {
// MARK: - Last Message Server ID
public static let lastMessageServerIDCollection = "LokiGroupChatLastMessageServerIDCollection"
public static let lastMessageServerIDCollection = "SNLastMessageServerIDCollection"
public func getLastMessageServerID(for group: UInt64, on server: String) -> UInt64? {
var result: UInt64? = nil
public func getLastMessageServerID(for room: String, on server: String) -> Int64? {
let collection = Storage.lastMessageServerIDCollection
let key = "\(server).\(room)"
var result: Int64? = nil
Storage.read { transaction in
result = transaction.object(forKey: "\(server).\(group)", inCollection: Storage.lastMessageServerIDCollection) as? UInt64
result = transaction.object(forKey: key, inCollection: collection) as? Int64
}
return result
}
public func setLastMessageServerID(for group: UInt64, on server: String, to newValue: UInt64, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: "\(server).\(group)", inCollection: Storage.lastMessageServerIDCollection)
public func setLastMessageServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any) {
let collection = Storage.lastMessageServerIDCollection
let key = "\(server).\(room)"
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: key, inCollection: collection)
}
public func removeLastMessageServerID(for group: UInt64, on server: String, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: "\(server).\(group)", inCollection: Storage.lastMessageServerIDCollection)
public func removeLastMessageServerID(for room: String, on server: String, using transaction: Any) {
let collection = Storage.lastMessageServerIDCollection
let key = "\(server).\(room)"
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: key, inCollection: collection)
}
// MARK: - Last Deletion Server ID
public static let lastDeletionServerIDCollection = "LokiGroupChatLastDeletionServerIDCollection"
public static let lastDeletionServerIDCollection = "SNLastDeletionServerIDCollection"
public func getLastDeletionServerID(for group: UInt64, on server: String) -> UInt64? {
var result: UInt64? = nil
public func getLastDeletionServerID(for room: String, on server: String) -> Int64? {
let collection = Storage.lastDeletionServerIDCollection
let key = "\(server).\(room)"
var result: Int64? = nil
Storage.read { transaction in
result = transaction.object(forKey: "\(server).\(group)", inCollection: Storage.lastDeletionServerIDCollection) as? UInt64
result = transaction.object(forKey: key, inCollection: collection) as? Int64
}
return result
}
public func setLastDeletionServerID(for group: UInt64, on server: String, to newValue: UInt64, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: "\(server).\(group)", inCollection: Storage.lastDeletionServerIDCollection)
public func setLastDeletionServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any) {
let collection = Storage.lastDeletionServerIDCollection
let key = "\(server).\(room)"
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: key, inCollection: collection)
}
public func removeLastDeletionServerID(for group: UInt64, on server: String, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: "\(server).\(group)", inCollection: Storage.lastDeletionServerIDCollection)
public func removeLastDeletionServerID(for room: String, on server: String, using transaction: Any) {
let collection = Storage.lastDeletionServerIDCollection
let key = "\(server).\(room)"
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: key, inCollection: collection)
}
@ -240,4 +252,40 @@ extension Storage {
let collection = Storage.getAuthTokenCollection(for: server)
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: server, inCollection: collection)
}
public static let oldLastMessageServerIDCollection = "LokiGroupChatLastMessageServerIDCollection"
public func getLastMessageServerID(for group: UInt64, on server: String) -> UInt64? {
var result: UInt64? = nil
Storage.read { transaction in
result = transaction.object(forKey: "\(server).\(group)", inCollection: Storage.oldLastMessageServerIDCollection) as? UInt64
}
return result
}
public func setLastMessageServerID(for group: UInt64, on server: String, to newValue: UInt64, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: "\(server).\(group)", inCollection: Storage.oldLastMessageServerIDCollection)
}
public func removeLastMessageServerID(for group: UInt64, on server: String, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: "\(server).\(group)", inCollection: Storage.oldLastMessageServerIDCollection)
}
public static let oldLastDeletionServerIDCollection = "LokiGroupChatLastDeletionServerIDCollection"
public func getLastDeletionServerID(for group: UInt64, on server: String) -> UInt64? {
var result: UInt64? = nil
Storage.read { transaction in
result = transaction.object(forKey: "\(server).\(group)", inCollection: Storage.oldLastDeletionServerIDCollection) as? UInt64
}
return result
}
public func setLastDeletionServerID(for group: UInt64, on server: String, to newValue: UInt64, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: "\(server).\(group)", inCollection: Storage.oldLastDeletionServerIDCollection)
}
public func removeLastDeletionServerID(for group: UInt64, on server: String, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: "\(server).\(group)", inCollection: Storage.oldLastDeletionServerIDCollection)
}
}

View File

@ -1,6 +1,8 @@
import PromiseKit
import SessionSnodeKit
// TODO: Message signature validation
public enum OpenGroupAPIV2 {
// MARK: Error
@ -70,8 +72,12 @@ public enum OpenGroupAPIV2 {
tsRequest.setValue(request.room, forKey: "Room")
if request.useOnionRouting {
guard let publicKey = SNMessagingKitConfiguration.shared.storage.getOpenGroupPublicKey(for: request.server) else { return Promise(error: Error.noPublicKey) }
return getAuthToken(for: request.room, on: request.server).then(on: DispatchQueue.global(qos: .default)) { authToken -> Promise<JSON> in
tsRequest.setValue(authToken, forKey: "Authorization")
if request.isAuthRequired {
return getAuthToken(for: request.room, on: request.server).then(on: DispatchQueue.global(qos: .default)) { authToken -> Promise<JSON> in
tsRequest.setValue(authToken, forKey: "Authorization")
return OnionRequestAPI.sendOnionRequest(tsRequest, to: request.server, using: publicKey)
}
} else {
return OnionRequestAPI.sendOnionRequest(tsRequest, to: request.server, using: publicKey)
}
} else {
@ -125,7 +131,12 @@ public enum OpenGroupAPIV2 {
/// Should be called when leaving a group.
public static func deleteAuthToken(for room: String, on server: String) -> Promise<Void> {
let request = Request(verb: .delete, room: room, server: server, endpoint: "auth_token")
return send(request).map(on: DispatchQueue.global(qos: .userInitiated)) { _ in }
return send(request).map(on: DispatchQueue.global(qos: .userInitiated)) { _ in
let storage = SNMessagingKitConfiguration.shared.storage
storage.write { transaction in
storage.removeAuthToken(for: room, on: server, using: transaction)
}
}
}
// MARK: File Storage
@ -159,20 +170,35 @@ public enum OpenGroupAPIV2 {
}
public static func getMessages(for room: String, on server: String) -> Promise<[OpenGroupMessageV2]> {
// TODO: From server ID & limit
let queryParameters: [String:String] = [:]
let storage = SNMessagingKitConfiguration.shared.storage
var queryParameters: [String:String] = [:]
if let lastMessageServerID = storage.getLastMessageServerID(for: room, on: server) {
queryParameters["from_server_id"] = String(lastMessageServerID)
}
let request = Request(verb: .get, room: room, server: server, endpoint: "messages", queryParameters: queryParameters)
return send(request).map(on: DispatchQueue.global(qos: .userInitiated)) { json in
return send(request).then(on: DispatchQueue.global(qos: .userInitiated)) { json -> Promise<[OpenGroupMessageV2]> in
guard let rawMessages = json["messages"] as? [[String:Any]] else { throw Error.parsingFailed }
let messages: [OpenGroupMessageV2] = rawMessages.compactMap { json in
// TODO: Signature validation
guard let message = OpenGroupMessageV2.fromJSON(json) else {
guard let message = OpenGroupMessageV2.fromJSON(json), message.serverID != nil else {
SNLog("Couldn't parse open group message from JSON: \(json).")
return nil
}
return message
}
return messages
let serverID = messages.map { $0.serverID! }.max() ?? 0 // Safe because messages with a nil serverID are filtered out above
let lastMessageServerID = storage.getLastMessageServerID(for: room, on: server) ?? 0
if serverID > lastMessageServerID {
let (promise, seal) = Promise<[OpenGroupMessageV2]>.pending()
storage.write(with: { transaction in
storage.setLastMessageServerID(for: room, on: server, to: serverID, using: transaction)
}, completion: {
seal.fulfill(messages)
})
return promise
} else {
return Promise.value(messages)
}
}
}
@ -183,12 +209,27 @@ public enum OpenGroupAPIV2 {
}
public static func getDeletedMessages(for room: String, on server: String) -> Promise<[Int64]> {
// TODO: From server ID & limit
let queryParameters: [String:String] = [:]
let storage = SNMessagingKitConfiguration.shared.storage
var queryParameters: [String:String] = [:]
if let lastDeletionServerID = storage.getLastDeletionServerID(for: room, on: server) {
queryParameters["from_server_id"] = String(lastDeletionServerID)
}
let request = Request(verb: .get, room: room, server: server, endpoint: "deleted_messages", queryParameters: queryParameters)
return send(request).map(on: DispatchQueue.global(qos: .userInitiated)) { json in
guard let ids = json["ids"] as? [Int64] else { throw Error.parsingFailed }
return ids
return send(request).then(on: DispatchQueue.global(qos: .userInitiated)) { json -> Promise<[Int64]> in
guard let serverIDs = json["ids"] as? [Int64] else { throw Error.parsingFailed }
let serverID = serverIDs.max() ?? 0
let lastDeletionServerID = storage.getLastDeletionServerID(for: room, on: server) ?? 0
if serverID > lastDeletionServerID {
let (promise, seal) = Promise<[Int64]>.pending()
storage.write(with: { transaction in
storage.setLastDeletionServerID(for: room, on: server, to: serverID, using: transaction)
}, completion: {
seal.fulfill(serverIDs)
})
return promise
} else {
return Promise.value(serverIDs)
}
}
}

View File

@ -55,15 +55,15 @@ public protocol SessionMessagingKitStorageProtocol {
// MARK: - Last Message Server ID
func getLastMessageServerID(for group: UInt64, on server: String) -> UInt64?
func setLastMessageServerID(for group: UInt64, on server: String, to newValue: UInt64, using transaction: Any)
func removeLastMessageServerID(for group: UInt64, on server: String, using transaction: Any)
func getLastMessageServerID(for room: String, on server: String) -> Int64?
func setLastMessageServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any)
func removeLastMessageServerID(for room: String, on server: String, using transaction: Any)
// MARK: - Last Deletion Server ID
func getLastDeletionServerID(for group: UInt64, on server: String) -> UInt64?
func setLastDeletionServerID(for group: UInt64, on server: String, to newValue: UInt64, using transaction: Any)
func removeLastDeletionServerID(for group: UInt64, on server: String, using transaction: Any)
func getLastDeletionServerID(for room: String, on server: String) -> Int64?
func setLastDeletionServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any)
func removeLastDeletionServerID(for room: String, on server: String, using transaction: Any)
// MARK: - Open Group Metadata
@ -93,4 +93,12 @@ public protocol SessionMessagingKitStorageProtocol {
func getAuthToken(for server: String) -> String?
func setAuthToken(for server: String, to newValue: String, using transaction: Any)
func removeAuthToken(for server: String, using transaction: Any)
func getLastMessageServerID(for group: UInt64, on server: String) -> UInt64?
func setLastMessageServerID(for group: UInt64, on server: String, to newValue: UInt64, using transaction: Any)
func removeLastMessageServerID(for group: UInt64, on server: String, using transaction: Any)
func getLastDeletionServerID(for group: UInt64, on server: String) -> UInt64?
func setLastDeletionServerID(for group: UInt64, on server: String, to newValue: UInt64, using transaction: Any)
func removeLastDeletionServerID(for group: UInt64, on server: String, using transaction: Any)
}