diff --git a/Signal/src/Loki/LokiGroupChatPoller.swift b/Signal/src/Loki/LokiGroupChatPoller.swift index 80fc535fd..b097031da 100644 --- a/Signal/src/Loki/LokiGroupChatPoller.swift +++ b/Signal/src/Loki/LokiGroupChatPoller.swift @@ -58,6 +58,15 @@ public final class LokiGroupChatPoller : NSObject { } private func pollForDeletedMessages() { - // TODO: Implement + let group = self.group + let _ = LokiGroupChatAPI.getDeletedMessageIDs(for: group.serverID, on: group.server).done { deletedMessageServerIDs in + let storage = OWSPrimaryStorage.shared() + storage.dbReadWriteConnection.readWrite { transaction in + let deletedMessageIDs = deletedMessageServerIDs.compactMap { storage.getIDForMessage(withServerID: UInt($0), in: transaction) } + deletedMessageIDs.forEach { messageID in + TSMessage.fetch(uniqueId: messageID)?.remove(with: transaction) + } + } + } } } diff --git a/SignalServiceKit/src/Loki/API/LokiGroupChat.swift b/SignalServiceKit/src/Loki/API/LokiGroupChat.swift index ba0c7a7cd..0f5ec66be 100644 --- a/SignalServiceKit/src/Loki/API/LokiGroupChat.swift +++ b/SignalServiceKit/src/Loki/API/LokiGroupChat.swift @@ -2,12 +2,12 @@ @objc(LKGroupChat) public final class LokiGroupChat : NSObject { @objc public let id: String - @objc public let serverID: UInt + @objc public let serverID: UInt64 @objc public let server: String @objc public let displayName: String @objc public let isDeletable: Bool - @objc public init(serverID: UInt, server: String, displayName: String, isDeletable: Bool) { + @objc public init(serverID: UInt64, server: String, displayName: String, isDeletable: Bool) { self.id = "\(server).\(serverID)" self.serverID = serverID self.server = server diff --git a/SignalServiceKit/src/Loki/API/LokiGroupChatAPI.swift b/SignalServiceKit/src/Loki/API/LokiGroupChatAPI.swift index 023a8ad74..5e3cfae00 100644 --- a/SignalServiceKit/src/Loki/API/LokiGroupChatAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiGroupChatAPI.swift @@ -50,7 +50,7 @@ public final class LokiGroupChatAPI : NSObject { } } - private static func getLastMessageServerID(for group: UInt, on server: String) -> UInt? { + private static func getLastMessageServerID(for group: UInt64, on server: String) -> UInt? { var result: UInt? = nil storage.dbReadConnection.read { transaction in result = transaction.object(forKey: "\(server).\(group)", inCollection: lastMessageServerIDCollection) as! UInt? @@ -58,13 +58,13 @@ public final class LokiGroupChatAPI : NSObject { return result } - private static func setLastMessageServerID(for group: UInt, on server: String, to newValue: UInt) { + private static func setLastMessageServerID(for group: UInt64, on server: String, to newValue: UInt64) { storage.dbReadWriteConnection.readWrite { transaction in transaction.setObject(newValue, forKey: "\(server).\(group)", inCollection: lastMessageServerIDCollection) } } - private static func getFirstMessageServerID(for group: UInt, on server: String) -> UInt? { + private static func getFirstMessageServerID(for group: UInt64, on server: String) -> UInt? { var result: UInt? = nil storage.dbReadConnection.read { transaction in result = transaction.object(forKey: "\(server).\(group)", inCollection: firstMessageServerIDCollection) as! UInt? @@ -72,7 +72,7 @@ public final class LokiGroupChatAPI : NSObject { return result } - private static func setFirstMessageServerID(for group: UInt, on server: String, to newValue: UInt) { + private static func setFirstMessageServerID(for group: UInt64, on server: String, to newValue: UInt64) { storage.dbReadWriteConnection.readWrite { transaction in transaction.setObject(newValue, forKey: "\(server).\(group)", inCollection: firstMessageServerIDCollection) } @@ -123,7 +123,7 @@ public final class LokiGroupChatAPI : NSObject { } // MARK: Public API - public static func getMessages(for group: UInt, on server: String) -> Promise<[LokiGroupMessage]> { + public static func getMessages(for group: UInt64, on server: String) -> Promise<[LokiGroupMessage]> { print("[Loki] Getting messages for group chat with ID: \(group) on server: \(server).") var queryParameters = "include_annotations=1" if let lastMessageServerID = getLastMessageServerID(for: group, on: server) { @@ -140,7 +140,7 @@ public final class LokiGroupChatAPI : NSObject { } return rawMessages.flatMap { message in guard let annotations = message["annotations"] as? [JSON], let annotation = annotations.first, let value = annotation["value"] as? JSON, - let serverID = message["id"] as? UInt, let body = message["text"] as? String, let hexEncodedPublicKey = value["source"] as? String, let displayName = value["from"] as? String, + let serverID = message["id"] as? UInt64, let body = message["text"] as? String, let hexEncodedPublicKey = value["source"] as? String, let displayName = value["from"] as? String, let timestamp = value["timestamp"] as? UInt64 else { print("[Loki] Couldn't parse message for group chat with ID: \(group) on server: \(server) from: \(message).") return nil @@ -155,7 +155,7 @@ public final class LokiGroupChatAPI : NSObject { } } - public static func sendMessage(_ message: LokiGroupMessage, to group: UInt, on server: String) -> Promise { + public static func sendMessage(_ message: LokiGroupMessage, to group: UInt64, on server: String) -> Promise { return getAuthToken(for: server).then { token -> Promise in print("[Loki] Sending message to group chat with ID: \(group) on server: \(server).") let url = URL(string: "\(server)/channels/\(group)/messages")! @@ -167,7 +167,7 @@ public final class LokiGroupChatAPI : NSObject { // ISO8601DateFormatter doesn't support milliseconds before iOS 11 let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" - guard let json = rawResponse as? JSON, let messageAsJSON = json["data"] as? JSON, let serverID = messageAsJSON["id"] as? UInt, let body = messageAsJSON["text"] as? String, + guard let json = rawResponse as? JSON, let messageAsJSON = json["data"] as? JSON, let serverID = messageAsJSON["id"] as? UInt64, let body = messageAsJSON["text"] as? String, let dateAsString = messageAsJSON["created_at"] as? String, let date = dateFormatter.date(from: dateAsString) else { print("[Loki] Couldn't parse message for group chat with ID: \(group) on server: \(server) from: \(rawResponse).") throw Error.messageParsingFailed @@ -184,7 +184,7 @@ public final class LokiGroupChatAPI : NSObject { }.retryingIfNeeded(maxRetryCount: maxRetryCount) } - public static func getDeletedMessageIDs(for group: UInt, on server: String) -> Promise<[UInt]> { + public static func getDeletedMessageIDs(for group: UInt64, on server: String) -> Promise<[UInt64]> { print("[Loki] Getting deleted messages for group chat with ID: \(group) on server: \(server).") let firstMessageServerID = getFirstMessageServerID(for: group, on: server) ?? 0 let queryParameters = "is_deleted=true&since_id=\(firstMessageServerID)" @@ -196,7 +196,7 @@ public final class LokiGroupChatAPI : NSObject { throw Error.messageParsingFailed } return rawMessages.flatMap { message in - guard let serverID = message["id"] as? UInt else { + guard let serverID = message["id"] as? UInt64 else { print("[Loki] Couldn't parse deleted message for group chat with ID: \(group) on server: \(server) from: \(message).") return nil } @@ -208,12 +208,12 @@ public final class LokiGroupChatAPI : NSObject { // MARK: Public API (Obj-C) @objc(getMessagesForGroup:onServer:) - public static func objc_getMessages(for group: UInt, on server: String) -> AnyPromise { + public static func objc_getMessages(for group: UInt64, on server: String) -> AnyPromise { return AnyPromise.from(getMessages(for: group, on: server)) } @objc(sendMessage:toGroup:onServer:) - public static func objc_sendMessage(_ message: LokiGroupMessage, to group: UInt, on server: String) -> AnyPromise { + public static func objc_sendMessage(_ message: LokiGroupMessage, to group: UInt64, on server: String) -> AnyPromise { return AnyPromise.from(sendMessage(message, to: group, on: server)) } } diff --git a/SignalServiceKit/src/Loki/API/LokiGroupMessage.swift b/SignalServiceKit/src/Loki/API/LokiGroupMessage.swift index 53d053531..7d6d3b974 100644 --- a/SignalServiceKit/src/Loki/API/LokiGroupMessage.swift +++ b/SignalServiceKit/src/Loki/API/LokiGroupMessage.swift @@ -2,7 +2,7 @@ import PromiseKit @objc(LKGroupMessage) public final class LokiGroupMessage : NSObject { - public let serverID: UInt? + public let serverID: UInt64? public let hexEncodedPublicKey: String public let displayName: String public let body: String @@ -10,7 +10,10 @@ public final class LokiGroupMessage : NSObject { public let timestamp: UInt64 public let type: String - public init(serverID: UInt?, hexEncodedPublicKey: String, displayName: String, body: String, type: String, timestamp: UInt64) { + @objc(serverID) + public var objc_serverID: UInt64 { return serverID ?? 0 } + + public init(serverID: UInt64?, hexEncodedPublicKey: String, displayName: String, body: String, type: String, timestamp: UInt64) { self.serverID = serverID self.hexEncodedPublicKey = hexEncodedPublicKey self.displayName = displayName diff --git a/SignalServiceKit/src/Loki/Crypto/OWSPrimaryStorage+Loki.h b/SignalServiceKit/src/Loki/Crypto/OWSPrimaryStorage+Loki.h index d74f63696..53a9a1ba4 100644 --- a/SignalServiceKit/src/Loki/Crypto/OWSPrimaryStorage+Loki.h +++ b/SignalServiceKit/src/Loki/Crypto/OWSPrimaryStorage+Loki.h @@ -95,6 +95,9 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)setLastMessageHashForServiceNode:(NSString *)serviceNode hash:(NSString *)hash expiresAt:(u_int64_t)expiresAt transaction:(YapDatabaseReadWriteTransaction *)transaction NS_SWIFT_NAME(setLastMessageHash(forServiceNode:hash:expiresAt:transaction:)); +- (void)setIDForMessageWithServerID:(NSUInteger)serverID to:(NSString *)messageID in:(YapDatabaseReadWriteTransaction *)transaction; +- (NSString *)getIDForMessageWithServerID:(NSUInteger)serverID in:(YapDatabaseReadTransaction *)transaction; + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Loki/Crypto/OWSPrimaryStorage+Loki.m b/SignalServiceKit/src/Loki/Crypto/OWSPrimaryStorage+Loki.m index 1e72f3830..17f778a6c 100644 --- a/SignalServiceKit/src/Loki/Crypto/OWSPrimaryStorage+Loki.m +++ b/SignalServiceKit/src/Loki/Crypto/OWSPrimaryStorage+Loki.m @@ -18,6 +18,7 @@ #define LKLastMessageHashCollection @"LKLastMessageHashCollection" #define LKReceivedMessageHashesKey @"LKReceivedMessageHashesKey" #define LKReceivedMessageHashesCollection @"LKReceivedMessageHashesCollection" +#define LKMessageIDCollection @"LKMessageIDCollection" @implementation OWSPrimaryStorage (Loki) @@ -162,4 +163,14 @@ [transaction removeObjectForKey:serviceNode inCollection:LKLastMessageHashCollection]; } +- (void)setIDForMessageWithServerID:(NSUInteger)serverID to:(NSString *)messageID in:(YapDatabaseReadWriteTransaction *)transaction { + NSString *key = [NSString stringWithFormat:@"%@", @(serverID)]; + [transaction setObject:messageID forKey:key inCollection:LKMessageIDCollection]; +} + +- (NSString *)getIDForMessageWithServerID:(NSUInteger)serverID in:(YapDatabaseReadTransaction *)transaction { + NSString *key = [NSString stringWithFormat:@"%@", @(serverID)]; + return [transaction objectForKey:key inCollection:LKMessageIDCollection]; +} + @end diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 6930ec5c7..369b089ad 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1115,7 +1115,10 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; if (displayName == nil) { displayName = @"Anonymous"; } LKGroupMessage *groupMessage = [[LKGroupMessage alloc] initWithHexEncodedPublicKey:userHexEncodedPublicKey displayName:displayName body:message.body type:LKGroupChatAPI.publicChatMessageType timestamp:message.timestamp]; [[LKGroupChatAPI sendMessage:groupMessage toGroup:LKGroupChatAPI.publicChatServerID onServer:LKGroupChatAPI.publicChatServer] - .thenOn(OWSDispatch.sendingQueue, ^(id result) { + .thenOn(OWSDispatch.sendingQueue, ^(LKGroupMessage *groupMessage) { + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [OWSPrimaryStorage.sharedManager setIDForMessageWithServerID:groupMessage.serverID to:message.uniqueId in:transaction]; + }]; [self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:false wasSentByWebsocket:false]; }) .catchOn(OWSDispatch.sendingQueue, ^(NSError *error) { // The snode is unreachable