From 7331e7fa312367c56b708673ed47d93818c243bb Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 21 Oct 2019 11:43:46 +1100 Subject: [PATCH] Ditch temporary link preview setup --- .../ConversationViewController.m | 4 ++-- SignalServiceKit/protobuf/SignalService.proto | 18 +++++++-------- .../API/Public Chat/LokiPublicChatAPI.swift | 9 ++++++-- .../Public Chat/LokiPublicChatMessage.swift | 22 ++++++++++++++----- .../Public Chat/LokiPublicChatPoller.swift | 20 ++++++++++++++++- .../Interactions/OWSLinkPreview.swift | 4 +--- .../src/Messages/OWSMessageManager.m | 20 ----------------- .../src/Messages/OWSMessageSender.m | 11 +++++++--- 8 files changed, 63 insertions(+), 45 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index e2b10ce3c..3c498e08b 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -2162,7 +2162,7 @@ typedef enum : NSUInteger { NSValue *_Nullable contentOffset = [self contentOffsetForMenuActionInteraction]; if (contentOffset == nil) { - // OWSFailDebug(@"Missing contentOffset."); +// OWSFailDebug(@"Missing contentOffset."); return; } [self.collectionView setContentOffset:contentOffset.CGPointValue animated:animated]; @@ -2192,7 +2192,7 @@ typedef enum : NSUInteger { UICollectionViewLayoutAttributes *_Nullable layoutAttributes = [self.layout layoutAttributesForItemAtIndexPath:indexPath]; if (layoutAttributes == nil) { - // OWSFailDebug(@"Missing layoutAttributes."); +// OWSFailDebug(@"Missing layoutAttributes."); return nil; } CGRect cellFrame = layoutAttributes.frame; diff --git a/SignalServiceKit/protobuf/SignalService.proto b/SignalServiceKit/protobuf/SignalService.proto index 1cf2d9d88..e9eac11ab 100644 --- a/SignalServiceKit/protobuf/SignalService.proto +++ b/SignalServiceKit/protobuf/SignalService.proto @@ -58,14 +58,14 @@ message TypingMessage { } message Content { - optional DataMessage dataMessage = 1; - optional SyncMessage syncMessage = 2; - optional CallMessage callMessage = 3; - optional NullMessage nullMessage = 4; - optional ReceiptMessage receiptMessage = 5; - optional TypingMessage typingMessage = 6; - optional PrekeyBundleMessage prekeyBundleMessage = 101; // Loki - optional LokiAddressMessage lokiAddressMessage = 102; // Loki + optional DataMessage dataMessage = 1; + optional SyncMessage syncMessage = 2; + optional CallMessage callMessage = 3; + optional NullMessage nullMessage = 4; + optional ReceiptMessage receiptMessage = 5; + optional TypingMessage typingMessage = 6; + optional PrekeyBundleMessage prekeyBundleMessage = 101; // Loki + optional LokiAddressMessage lokiAddressMessage = 102; // Loki optional LokiDeviceLinkMessage lokiDeviceLinkMessage = 103; // Loki } @@ -311,7 +311,7 @@ message SyncMessage { optional AttachmentPointer blob = 1; // Signal-iOS renamed this property. optional bool isComplete = 2 [default = false]; - optional bytes data = 101; // Loki + optional bytes data = 101; // Loki } message Groups { diff --git a/SignalServiceKit/src/Loki/API/Public Chat/LokiPublicChatAPI.swift b/SignalServiceKit/src/Loki/API/Public Chat/LokiPublicChatAPI.swift index 8739b4c3b..b41e6d65c 100644 --- a/SignalServiceKit/src/Loki/API/Public Chat/LokiPublicChatAPI.swift +++ b/SignalServiceKit/src/Loki/API/Public Chat/LokiPublicChatAPI.swift @@ -111,9 +111,14 @@ public final class LokiPublicChatAPI : LokiDotNetAPI { let signature = LokiPublicChatMessage.Signature(data: Data(hex: hexEncodedSignatureData), version: signatureVersion) let attachmentsAsJSON = annotations.filter { $0["type"] as? String == attachmentType } let attachments: [LokiPublicChatMessage.Attachment] = attachmentsAsJSON.compactMap { attachmentAsJSON in - guard let value = attachmentAsJSON["value"] as? JSON, let server = value["server"] as? String, let serverID = value["id"] as? UInt64, let contentType = value["contentType"] as? String, let size = value["size"] as? UInt, let fileName = value["fileName"] as? String, let flags = value["flags"] as? UInt, let width = value["width"] as? UInt, let height = value["height"] as? UInt, let url = value["url"] as? String else { return nil } + guard let value = attachmentAsJSON["value"] as? JSON, let kindAsString = value["lokiType"] as? String, let kind = LokiPublicChatMessage.Attachment.Kind(rawValue: kindAsString), let serverID = value["id"] as? UInt64, let contentType = value["contentType"] as? String, let size = value["size"] as? UInt, let fileName = value["fileName"] as? String, let flags = value["flags"] as? UInt, let width = value["width"] as? UInt, let height = value["height"] as? UInt, let url = value["url"] as? String else { return nil } let caption = value["caption"] as? String - return LokiPublicChatMessage.Attachment(server: server, serverID: serverID, contentType: contentType, size: size, fileName: fileName, flags: flags, width: width, height: height, caption: caption, url: url) + let linkPreviewURL = value["linkPreviewUrl"] as? String + let linkPreviewTitle = value["linkPreviewTitle"] as? String + if kind == .linkPreview { + guard linkPreviewURL != nil && linkPreviewTitle != nil else { return nil } + } + return LokiPublicChatMessage.Attachment(kind: kind, server: server, serverID: serverID, contentType: contentType, size: size, fileName: fileName, flags: flags, width: width, height: height, caption: caption, url: url, linkPreviewURL: linkPreviewURL, linkPreviewTitle: linkPreviewTitle) } let result = LokiPublicChatMessage(serverID: serverID, hexEncodedPublicKey: hexEncodedPublicKey, displayName: displayName, body: body, type: publicChatMessageType, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature) guard result.hasValidSignature() else { diff --git a/SignalServiceKit/src/Loki/API/Public Chat/LokiPublicChatMessage.swift b/SignalServiceKit/src/Loki/API/Public Chat/LokiPublicChatMessage.swift index c7c51ce58..95ec03859 100644 --- a/SignalServiceKit/src/Loki/API/Public Chat/LokiPublicChatMessage.swift +++ b/SignalServiceKit/src/Loki/API/Public Chat/LokiPublicChatMessage.swift @@ -29,6 +29,7 @@ public final class LokiPublicChatMessage : NSObject { } public struct Attachment { + public let kind: Kind public let server: String public let serverID: UInt64 public let contentType: String @@ -39,8 +40,12 @@ public final class LokiPublicChatMessage : NSObject { public let height: UInt public let caption: String? public let url: String + /// Guaranteed to be non-`nil` if `kind` is `linkPreview` + public let linkPreviewURL: String? + /// Guaranteed to be non-`nil` if `kind` is `linkPreview` + public let linkPreviewTitle: String? - public enum Kind : String { case photo, video } + public enum Kind : String { case attachment, linkPreview = "preview" } } public struct Signature { @@ -118,11 +123,17 @@ public final class LokiPublicChatMessage : NSObject { // Field required by the .NET API "version" : 1, "type" : type, // Custom fields - "server" : attachment.server, "id" : attachment.serverID, "contentType" : attachment.contentType, "size" : attachment.size, "fileName" : attachment.fileName, "flags" : attachment.flags, "width" : attachment.width, "height" : attachment.height, "url" : attachment.url + "lokiType" : attachment.kind.rawValue, "server" : attachment.server, "id" : attachment.serverID, "contentType" : attachment.contentType, "size" : attachment.size, "fileName" : attachment.fileName, "flags" : attachment.flags, "width" : attachment.width, "height" : attachment.height, "url" : attachment.url ] if let caption = attachment.caption { attachmentValue["caption"] = attachment.caption } + if let linkPreviewURL = attachment.linkPreviewURL { + attachmentValue["linkPreviewUrl"] = linkPreviewURL + } + if let linkPreviewTitle = attachment.linkPreviewTitle { + attachmentValue["linkPreviewTitle"] = linkPreviewTitle + } return [ "type" : attachmentType, "value" : attachmentValue ] } var result: JSON = [ "text" : body, "annotations": [ annotation ] + attachmentAnnotations ] @@ -133,8 +144,9 @@ public final class LokiPublicChatMessage : NSObject { } // MARK: Convenience - @objc public func addAttachment(server: String, serverID: UInt64, contentType: String, size: UInt, fileName: String, flags: UInt, width: UInt, height: UInt, caption: String?, url: String) { - let attachment = Attachment(server: server, serverID: serverID, contentType: contentType, size: size, fileName: fileName, flags: flags, width: width, height: height, caption: caption, url: url) + @objc public func addAttachment(kind: String, server: String, serverID: UInt64, contentType: String, size: UInt, fileName: String, flags: UInt, width: UInt, height: UInt, caption: String?, url: String, linkPreviewURL: String?, linkPreviewTitle: String?) { + guard let kind = Attachment.Kind(rawValue: kind) else { preconditionFailure() } + let attachment = Attachment(kind: kind, server: server, serverID: serverID, contentType: contentType, size: size, fileName: fileName, flags: flags, width: width, height: height, caption: caption, url: url, linkPreviewURL: linkPreviewURL, linkPreviewTitle: linkPreviewTitle) attachments.append(attachment) } @@ -146,7 +158,7 @@ public final class LokiPublicChatMessage : NSObject { string += "\(quotedMessageServerID)" } } - string += attachments.map { "\($0.serverID)" }.joined(separator: "") + string += attachments.sorted { $0.serverID < $1.serverID }.map { "\($0.serverID)" }.joined(separator: "") string += "\(signatureVersion)" return string.data(using: String.Encoding.utf8) } diff --git a/SignalServiceKit/src/Loki/API/Public Chat/LokiPublicChatPoller.swift b/SignalServiceKit/src/Loki/API/Public Chat/LokiPublicChatPoller.swift index 6b6c5f578..a2ba47a0f 100644 --- a/SignalServiceKit/src/Loki/API/Public Chat/LokiPublicChatPoller.swift +++ b/SignalServiceKit/src/Loki/API/Public Chat/LokiPublicChatPoller.swift @@ -54,7 +54,8 @@ public final class LokiPublicChatPoller : NSObject { let groupContext = SSKProtoGroupContext.builder(id: id, type: .deliver) groupContext.setName(publicChat.displayName) let dataMessage = SSKProtoDataMessage.builder() - let attachments: [SSKProtoAttachmentPointer] = message.attachments.map { attachment in + let attachments: [SSKProtoAttachmentPointer] = message.attachments.compactMap { attachment in + guard attachment.kind == .attachment else { return nil } let result = SSKProtoAttachmentPointer.builder(id: attachment.serverID) result.setContentType(attachment.contentType) result.setSize(UInt32(attachment.size)) @@ -69,6 +70,23 @@ public final class LokiPublicChatPoller : NSObject { return try! result.build() } dataMessage.setAttachments(attachments) + if let linkPreview = message.attachments.first(where: { $0.kind == .linkPreview }) { + let signalLinkPreview = SSKProtoDataMessagePreview.builder(url: linkPreview.linkPreviewURL!) + signalLinkPreview.setTitle(linkPreview.linkPreviewTitle!) + let attachment = SSKProtoAttachmentPointer.builder(id: linkPreview.serverID) + attachment.setContentType(linkPreview.contentType) + attachment.setSize(UInt32(linkPreview.size)) + attachment.setFileName(linkPreview.fileName) + attachment.setFlags(UInt32(linkPreview.flags)) + attachment.setWidth(UInt32(linkPreview.width)) + attachment.setHeight(UInt32(linkPreview.height)) + if let caption = linkPreview.caption { + attachment.setCaption(caption) + } + attachment.setUrl(linkPreview.url) + signalLinkPreview.setImage(try! attachment.build()) + dataMessage.setPreview([ try! signalLinkPreview.build() ]) + } dataMessage.setTimestamp(message.timestamp) dataMessage.setGroup(try! groupContext.build()) if let quote = message.quote { diff --git a/SignalServiceKit/src/Messages/Interactions/OWSLinkPreview.swift b/SignalServiceKit/src/Messages/Interactions/OWSLinkPreview.swift index 4306b14b2..da7181eef 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSLinkPreview.swift +++ b/SignalServiceKit/src/Messages/Interactions/OWSLinkPreview.swift @@ -172,7 +172,6 @@ public class OWSLinkPreview: MTLModel { } } - /* var imageAttachmentId: String? if let imageProto = previewProto.image { if let imageAttachmentPointer = TSAttachmentPointer(fromProto: imageProto, albumMessage: nil) { @@ -183,9 +182,8 @@ public class OWSLinkPreview: MTLModel { throw LinkPreviewError.invalidInput } } - */ - let linkPreview = OWSLinkPreview(urlString: urlString, title: title, imageAttachmentId: nil) + let linkPreview = OWSLinkPreview(urlString: urlString, title: title, imageAttachmentId: imageAttachmentId) guard linkPreview.isValid() else { Logger.error("Preview has neither title nor image.") diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index f4f89283b..b6606d6f1 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1427,14 +1427,6 @@ NS_ASSUME_NONNULL_BEGIN [self.primaryStorage setIDForMessageWithServerID:dataMessage.publicChatInfo.serverID to:incomingMessage.uniqueId in:transaction]; } - // Loki: Generate a link preview if needed - dispatch_async(dispatch_get_main_queue(), ^{ - NSString *linkPreviewURL = [OWSLinkPreview previewURLForRawBodyText:incomingMessage.body]; - if (linkPreviewURL != nil) { - [incomingMessage generateLinkPreviewIfNeededFromURL:linkPreviewURL]; - } - }); - return incomingMessage; } default: { @@ -1529,18 +1521,6 @@ NS_ASSUME_NONNULL_BEGIN envelope:envelope transaction:transaction]; - dispatch_async(dispatch_get_main_queue(), ^{ - NSString *linkPreviewURL; - if (linkPreview != nil) { - linkPreviewURL = linkPreview.urlString; - } else { - linkPreviewURL = [OWSLinkPreview previewURLForRawBodyText:incomingMessage.body]; - } - if (linkPreviewURL != nil) { - [incomingMessage generateLinkPreviewIfNeededFromURL:linkPreviewURL]; - } - }); - return incomingMessage; } } diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 32dc683e2..39311a02d 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1211,10 +1211,17 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; NSString *body = (message.body != nil && message.body.length > 0) ? message.body : [NSString stringWithFormat:@"%@", @(message.timestamp)]; // Workaround for the fact that the back-end doesn't accept messages without a body LKGroupMessage *groupMessage = [[LKGroupMessage alloc] initWithHexEncodedPublicKey:userHexEncodedPublicKey displayName:displayName body:body type:LKPublicChatAPI.publicChatMessageType timestamp:message.timestamp quotedMessageTimestamp:quoteID quoteeHexEncodedPublicKey:quoteeHexEncodedPublicKey quotedMessageBody:quote.body quotedMessageServerID:quotedMessageServerID signatureData:nil signatureVersion:0]; + OWSLinkPreview *linkPreview = message.linkPreview; + if (linkPreview != nil) { + TSAttachmentStream *attachment = [TSAttachmentStream fetchObjectWithUniqueID:linkPreview.imageAttachmentId]; + if (attachment != nil) { + [groupMessage addAttachmentWithKind:@"preview" server:publicChat.server serverID:attachment.serverId contentType:attachment.contentType size:attachment.byteCount fileName:attachment.sourceFilename flags:0 width:@(attachment.imageSize.width).unsignedIntegerValue height:@(attachment.imageSize.height).unsignedIntegerValue caption:attachment.caption url:attachment.downloadURL linkPreviewURL:linkPreview.urlString linkPreviewTitle:linkPreview.title]; + } + } for (NSString *attachmentID in message.attachmentIds) { TSAttachmentStream *attachment = [TSAttachmentStream fetchObjectWithUniqueID:attachmentID]; if (attachment == nil) { continue; } - [groupMessage addAttachmentWithServer:publicChat.server serverID:attachment.serverId contentType:attachment.contentType size:attachment.byteCount fileName:attachment.sourceFilename flags:0 width:@(attachment.imageSize.width).unsignedIntegerValue height:@(attachment.imageSize.height).unsignedIntegerValue caption:attachment.caption url:attachment.downloadURL]; + [groupMessage addAttachmentWithKind:@"attachment" server:publicChat.server serverID:attachment.serverId contentType:attachment.contentType size:attachment.byteCount fileName:attachment.sourceFilename flags:0 width:@(attachment.imageSize.width).unsignedIntegerValue height:@(attachment.imageSize.height).unsignedIntegerValue caption:attachment.caption url:attachment.downloadURL linkPreviewURL:nil linkPreviewTitle:nil]; } [[LKPublicChatAPI sendMessage:groupMessage toGroup:publicChat.channel onServer:publicChat.server] .thenOn(OWSDispatch.sendingQueue, ^(LKGroupMessage *groupMessage) { @@ -2090,7 +2097,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; } } - /* if (message.linkPreview.imageAttachmentId != nil) { TSAttachment *attachment = [TSAttachment fetchObjectWithUniqueID:message.linkPreview.imageAttachmentId transaction:transaction]; @@ -2100,7 +2106,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; OWSFailDebug(@"unexpected attachment: %@", attachment); } } - */ // All outgoing messages should be saved at the time they are enqueued. [message saveWithTransaction:transaction];