mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Merge branch 'charlesmchen/linkPreviews5a'
This commit is contained in:
commit
6ce6736269
13 changed files with 247 additions and 183 deletions
|
@ -3600,7 +3600,8 @@ typedef enum : NSUInteger {
|
|||
TSOutgoingMessage *message = [ThreadUtil enqueueMessageWithAttachments:attachments
|
||||
messageBody:messageText
|
||||
inThread:self.thread
|
||||
quotedReplyModel:self.inputToolbar.quotedReply];
|
||||
quotedReplyModel:self.inputToolbar.quotedReply
|
||||
linkPreview:nil];
|
||||
|
||||
[self messageWasSent:message];
|
||||
|
||||
|
@ -3977,7 +3978,8 @@ typedef enum : NSUInteger {
|
|||
// before the attachment is downloaded)
|
||||
message = [ThreadUtil enqueueMessageWithAttachment:attachment
|
||||
inThread:self.thread
|
||||
quotedReplyModel:self.inputToolbar.quotedReply];
|
||||
quotedReplyModel:self.inputToolbar.quotedReply
|
||||
linkPreview:nil];
|
||||
} else {
|
||||
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
message = [ThreadUtil enqueueMessageWithText:text
|
||||
|
|
|
@ -425,7 +425,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[DDLog flushLog];
|
||||
}
|
||||
OWSAssertDebug(![attachment hasError]);
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil];
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil linkPreview:nil];
|
||||
success();
|
||||
}
|
||||
|
||||
|
@ -1741,7 +1741,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSAssertDebug(thread);
|
||||
|
||||
SignalAttachment *attachment = [self signalAttachmentForFilePath:filePath];
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil];
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil linkPreview:nil];
|
||||
success();
|
||||
}
|
||||
|
||||
|
@ -3346,7 +3346,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithOversizeText:message];
|
||||
SignalAttachment *attachment =
|
||||
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:kOversizeTextAttachmentUTI];
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil];
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil linkPreview:nil];
|
||||
}
|
||||
|
||||
+ (NSData *)createRandomNSDataOfSize:(size_t)size
|
||||
|
@ -3379,7 +3379,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
// style them indistinguishably from a separate text message.
|
||||
attachment.captionText = [self randomCaptionText];
|
||||
}
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil];
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil linkPreview:nil];
|
||||
}
|
||||
|
||||
+ (SSKProtoEnvelope *)createEnvelopeForThread:(TSThread *)thread
|
||||
|
@ -4445,7 +4445,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[DDLog flushLog];
|
||||
}
|
||||
OWSAssertDebug(![attachment hasError]);
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil];
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil linkPreview:nil];
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
||||
sendUnsafeFile();
|
||||
|
@ -4763,7 +4763,8 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
TSOutgoingMessage *message = [ThreadUtil enqueueMessageWithAttachments:attachments
|
||||
messageBody:messageBody
|
||||
inThread:thread
|
||||
quotedReplyModel:nil];
|
||||
quotedReplyModel:nil
|
||||
linkPreview:nil];
|
||||
OWSLogError(@"timestamp: %llu.", message.timestamp);
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DebugUIMisc.h"
|
||||
#import "DebugUIMessagesAssetLoader.h"
|
||||
#import "OWSBackup.h"
|
||||
#import "OWSCountryMetadata.h"
|
||||
#import "OWSTableViewController.h"
|
||||
|
@ -20,7 +21,6 @@
|
|||
#import <SignalServiceKit/TSInvalidIdentityKeyReceivingErrorMessage.h>
|
||||
#import <SignalServiceKit/TSThread.h>
|
||||
#import <SignalServiceKit/UIImage+OWS.h>
|
||||
#import "DebugUIMessagesAssetLoader.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -257,7 +257,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSFailDebug(@"attachment[%@]: %@", [attachment sourceFilename], [attachment errorName]);
|
||||
return;
|
||||
}
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil];
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil linkPreview:nil];
|
||||
}
|
||||
|
||||
+ (void)sendUnencryptedDatabase:(TSThread *)thread
|
||||
|
@ -279,7 +279,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSFailDebug(@"attachment[%@]: %@", [attachment sourceFilename], [attachment errorName]);
|
||||
return;
|
||||
}
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil];
|
||||
[ThreadUtil enqueueMessageWithAttachment:attachment inThread:thread quotedReplyModel:nil linkPreview:nil];
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -53,12 +53,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
+ (TSOutgoingMessage *)enqueueMessageWithAttachment:(SignalAttachment *)attachment
|
||||
inThread:(TSThread *)thread
|
||||
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel;
|
||||
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
|
||||
linkPreview:(nullable OWSLinkPreview *)linkPreview;
|
||||
|
||||
+ (TSOutgoingMessage *)enqueueMessageWithAttachments:(NSArray<SignalAttachment *> *)attachments
|
||||
messageBody:(nullable NSString *)messageBody
|
||||
inThread:(TSThread *)thread
|
||||
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel;
|
||||
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
|
||||
linkPreview:(nullable OWSLinkPreview *)linkPreview;
|
||||
|
||||
+ (TSOutgoingMessage *)enqueueMessageWithContactShare:(OWSContact *)contactShare inThread:(TSThread *)thread;
|
||||
+ (void)enqueueLeaveGroupMessageInThread:(TSGroupThread *)thread;
|
||||
|
|
|
@ -99,19 +99,22 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
+ (TSOutgoingMessage *)enqueueMessageWithAttachment:(SignalAttachment *)attachment
|
||||
inThread:(TSThread *)thread
|
||||
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
|
||||
linkPreview:(nullable OWSLinkPreview *)linkPreview
|
||||
{
|
||||
return [self enqueueMessageWithAttachments:@[
|
||||
attachment,
|
||||
]
|
||||
messageBody:attachment.captionText
|
||||
inThread:thread
|
||||
quotedReplyModel:quotedReplyModel];
|
||||
quotedReplyModel:quotedReplyModel
|
||||
linkPreview:linkPreview];
|
||||
}
|
||||
|
||||
+ (TSOutgoingMessage *)enqueueMessageWithAttachments:(NSArray<SignalAttachment *> *)attachments
|
||||
messageBody:(nullable NSString *)messageBody
|
||||
inThread:(TSThread *)thread
|
||||
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
|
||||
linkPreview:(nullable OWSLinkPreview *)linkPreview
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(attachments.count > 0);
|
||||
|
@ -137,7 +140,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
groupMetaMessage:TSGroupMetaMessageUnspecified
|
||||
quotedMessage:[quotedReplyModel buildQuotedMessageForSending]
|
||||
contactShare:nil
|
||||
linkPreview:nil];
|
||||
linkPreview:linkPreview];
|
||||
|
||||
NSMutableArray<OWSOutgoingAttachmentInfo *> *attachmentInfos = [NSMutableArray new];
|
||||
for (SignalAttachment *attachment in attachments) {
|
||||
|
|
|
@ -222,7 +222,7 @@ message DataMessage {
|
|||
optional uint64 timestamp = 7;
|
||||
optional Quote quote = 8;
|
||||
repeated Contact contact = 9;
|
||||
optional Preview preview = 10;
|
||||
repeated Preview preview = 10;
|
||||
}
|
||||
|
||||
message NullMessage {
|
||||
|
|
|
@ -10,10 +10,10 @@ public enum LinkPreviewError: Int, Error {
|
|||
case noPreview
|
||||
}
|
||||
|
||||
// MARK: - OWSLinkPreviewInfo
|
||||
// MARK: - OWSLinkPreviewDraft
|
||||
|
||||
// This contains the info for a link preview "draft".
|
||||
public class OWSLinkPreviewInfo: NSObject {
|
||||
public class OWSLinkPreviewDraft: NSObject {
|
||||
@objc
|
||||
public var urlString: String
|
||||
|
||||
|
@ -39,6 +39,11 @@ public class OWSLinkPreviewInfo: NSObject {
|
|||
let hasImage = imageFilePath != nil
|
||||
return hasTitle || hasImage
|
||||
}
|
||||
|
||||
@objc
|
||||
public func displayDomain() -> String? {
|
||||
return OWSLinkPreview.displayDomain(forUrl: urlString)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - OWSLinkPreview
|
||||
|
@ -96,7 +101,7 @@ public class OWSLinkPreview: MTLModel {
|
|||
guard OWSLinkPreview.featureEnabled else {
|
||||
throw LinkPreviewError.noPreview
|
||||
}
|
||||
guard let previewProto = dataMessage.preview else {
|
||||
guard let previewProto = dataMessage.preview.first else {
|
||||
throw LinkPreviewError.noPreview
|
||||
}
|
||||
let urlString = previewProto.url
|
||||
|
@ -122,7 +127,13 @@ public class OWSLinkPreview: MTLModel {
|
|||
throw LinkPreviewError.invalidInput
|
||||
}
|
||||
|
||||
let title: String? = previewProto.title?.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
var title: String?
|
||||
if let rawTitle = previewProto.title?.trimmingCharacters(in: .whitespacesAndNewlines) {
|
||||
let normalizedTitle = OWSLinkPreview.normalizeTitle(title: rawTitle)
|
||||
if normalizedTitle.count > 0 {
|
||||
title = normalizedTitle
|
||||
}
|
||||
}
|
||||
|
||||
var imageAttachmentId: String?
|
||||
if let imageProto = previewProto.image {
|
||||
|
@ -146,7 +157,7 @@ public class OWSLinkPreview: MTLModel {
|
|||
}
|
||||
|
||||
@objc
|
||||
public class func buildValidatedLinkPreview(fromInfo info: OWSLinkPreviewInfo,
|
||||
public class func buildValidatedLinkPreview(fromInfo info: OWSLinkPreviewDraft,
|
||||
transaction: YapDatabaseReadWriteTransaction) throws -> OWSLinkPreview {
|
||||
guard OWSLinkPreview.featureEnabled else {
|
||||
throw LinkPreviewError.noPreview
|
||||
|
@ -187,8 +198,17 @@ public class OWSLinkPreview: MTLModel {
|
|||
owsFailDebug("Invalid content type for path: \(filePath)")
|
||||
return nil
|
||||
}
|
||||
guard let dataSource = DataSourcePath.dataSource(withFilePath: filePath, shouldDeleteOnDeallocation: true) else {
|
||||
owsFailDebug("Could not create data source for path: \(filePath)")
|
||||
return nil
|
||||
}
|
||||
let attachment = TSAttachmentStream(contentType: contentType, byteCount: fileSize.uint32Value, sourceFilename: nil, caption: nil, albumMessageId: nil)
|
||||
guard attachment.write(dataSource) else {
|
||||
owsFailDebug("Could not write data source for path: \(filePath)")
|
||||
return nil
|
||||
}
|
||||
attachment.save(with: transaction)
|
||||
|
||||
return attachment.uniqueId
|
||||
}
|
||||
|
||||
|
@ -214,6 +234,23 @@ public class OWSLinkPreview: MTLModel {
|
|||
attachment.remove(with: transaction)
|
||||
}
|
||||
|
||||
private class func normalizeTitle(title: String) -> String {
|
||||
var result = title
|
||||
// Truncate title after 2 lines of text.
|
||||
let maxLineCount = 2
|
||||
var components = result.components(separatedBy: .newlines)
|
||||
if components.count > maxLineCount {
|
||||
components = Array(components[0..<maxLineCount])
|
||||
result = components.joined(separator: "\n")
|
||||
}
|
||||
let maxCharacterCount = 2048
|
||||
if result.count > maxCharacterCount {
|
||||
let endIndex = result.index(result.startIndex, offsetBy: maxCharacterCount)
|
||||
result = String(result[...endIndex])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// MARK: - Domain Whitelist
|
||||
|
||||
// TODO: Finalize
|
||||
|
@ -235,13 +272,36 @@ public class OWSLinkPreview: MTLModel {
|
|||
"https"
|
||||
]
|
||||
|
||||
@objc
|
||||
public func displayDomain() -> String? {
|
||||
return OWSLinkPreview.displayDomain(forUrl: urlString)
|
||||
}
|
||||
|
||||
@objc
|
||||
public class func displayDomain(forUrl urlString: String?) -> String? {
|
||||
guard let urlString = urlString else {
|
||||
owsFailDebug("Missing url.")
|
||||
return nil
|
||||
}
|
||||
guard let url = URL(string: urlString) else {
|
||||
owsFailDebug("Invalid url.")
|
||||
return nil
|
||||
}
|
||||
guard let result = whitelistedDomain(forUrl: url,
|
||||
domainWhitelist: OWSLinkPreview.linkDomainWhitelist) else {
|
||||
owsFailDebug("Missing domain.")
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@objc
|
||||
public class func isValidLinkUrl(_ urlString: String) -> Bool {
|
||||
guard let url = URL(string: urlString) else {
|
||||
return false
|
||||
}
|
||||
return isUrlInDomainWhitelist(url: url,
|
||||
domainWhitelist: OWSLinkPreview.linkDomainWhitelist)
|
||||
return whitelistedDomain(forUrl: url,
|
||||
domainWhitelist: OWSLinkPreview.linkDomainWhitelist) != nil
|
||||
}
|
||||
|
||||
@objc
|
||||
|
@ -249,19 +309,19 @@ public class OWSLinkPreview: MTLModel {
|
|||
guard let url = URL(string: urlString) else {
|
||||
return false
|
||||
}
|
||||
return isUrlInDomainWhitelist(url: url,
|
||||
domainWhitelist: OWSLinkPreview.linkDomainWhitelist + OWSLinkPreview.mediaDomainWhitelist)
|
||||
return whitelistedDomain(forUrl: url,
|
||||
domainWhitelist: OWSLinkPreview.linkDomainWhitelist + OWSLinkPreview.mediaDomainWhitelist) != nil
|
||||
}
|
||||
|
||||
private class func isUrlInDomainWhitelist(url: URL, domainWhitelist: [String]) -> Bool {
|
||||
private class func whitelistedDomain(forUrl url: URL, domainWhitelist: [String]) -> String? {
|
||||
guard let urlProtocol = url.scheme?.lowercased() else {
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
guard protocolWhitelist.contains(urlProtocol) else {
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
guard let domain = url.host?.lowercased() else {
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
// TODO: We need to verify:
|
||||
//
|
||||
|
@ -273,10 +333,10 @@ public class OWSLinkPreview: MTLModel {
|
|||
for whitelistedDomain in domainWhitelist {
|
||||
if domain == whitelistedDomain.lowercased() ||
|
||||
domain.hasSuffix("." + whitelistedDomain.lowercased()) {
|
||||
return true
|
||||
return whitelistedDomain
|
||||
}
|
||||
}
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
|
||||
// MARK: - Serial Queue
|
||||
|
@ -291,16 +351,16 @@ public class OWSLinkPreview: MTLModel {
|
|||
|
||||
// MARK: - Text Parsing
|
||||
|
||||
// This cache should only be accessed on serialQueue.
|
||||
// This cache should only be accessed on main thread.
|
||||
private static var previewUrlCache: NSCache<AnyObject, AnyObject> = NSCache()
|
||||
|
||||
private class func previewUrl(forMessageBodyText body: String?) -> String? {
|
||||
assertIsOnSerialQueue()
|
||||
@objc
|
||||
public class func previewUrl(forMessageBodyText body: String?) -> String? {
|
||||
AssertIsOnMainThread()
|
||||
|
||||
guard OWSLinkPreview.featureEnabled else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let body = body else {
|
||||
return nil
|
||||
}
|
||||
|
@ -324,33 +384,35 @@ public class OWSLinkPreview: MTLModel {
|
|||
// MARK: - Preview Construction
|
||||
|
||||
// This cache should only be accessed on serialQueue.
|
||||
private static var linkPreviewInfoCache: NSCache<AnyObject, OWSLinkPreviewInfo> = NSCache()
|
||||
private static var linkPreviewDraftCache: NSCache<AnyObject, OWSLinkPreviewDraft> = NSCache()
|
||||
|
||||
// Completion will always be invoked exactly once.
|
||||
//
|
||||
// The completion is called with a link preview if one can be built for
|
||||
// the message body. It building the preview fails, completion will be
|
||||
// called with nil to avoid failing the message send.
|
||||
//
|
||||
// NOTE: Completion might be invoked on any thread.
|
||||
@objc
|
||||
public class func tryToBuildPreviewInfo(forMessageBodyText body: String?,
|
||||
completion: @escaping (OWSLinkPreviewInfo?) -> Void) {
|
||||
public class func tryToBuildPreviewInfo(previewUrl: String?,
|
||||
callbackQueue: DispatchQueue,
|
||||
completion completionParam: @escaping (OWSLinkPreviewDraft?) -> Void) {
|
||||
|
||||
// Ensure we invoke completion on the callback queue.
|
||||
let completion = { (linkPreviewDraft) in
|
||||
callbackQueue.async {
|
||||
completionParam(linkPreviewDraft)
|
||||
}
|
||||
}
|
||||
|
||||
guard OWSLinkPreview.featureEnabled else {
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
guard let body = body else {
|
||||
guard let previewUrl = previewUrl else {
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
serialQueue.async {
|
||||
guard let previewUrl = previewUrl(forMessageBodyText: body) else {
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
|
||||
if let cachedInfo = linkPreviewInfoCache.object(forKey: previewUrl as AnyObject) {
|
||||
if let cachedInfo = linkPreviewDraftCache.object(forKey: previewUrl as AnyObject) {
|
||||
Logger.verbose("Link preview info cache hit.")
|
||||
completion(cachedInfo)
|
||||
return
|
||||
|
@ -361,21 +423,19 @@ public class OWSLinkPreview: MTLModel {
|
|||
completion(nil)
|
||||
return
|
||||
}
|
||||
parse(linkData: data, linkUrlString: previewUrl) { (linkPreviewInfo) in
|
||||
guard let linkPreviewInfo = linkPreviewInfo else {
|
||||
parse(linkData: data, linkUrlString: previewUrl) { (linkPreviewDraft) in
|
||||
guard let linkPreviewDraft = linkPreviewDraft else {
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
guard linkPreviewInfo.isValid() else {
|
||||
guard linkPreviewDraft.isValid() else {
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
serialQueue.async {
|
||||
previewUrlCache.setObject(linkPreviewInfo, forKey: previewUrl as AnyObject)
|
||||
previewUrlCache.setObject(linkPreviewDraft, forKey: previewUrl as AnyObject)
|
||||
|
||||
DispatchQueue.global().async {
|
||||
completion(linkPreviewInfo)
|
||||
}
|
||||
completion(linkPreviewDraft)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -448,30 +508,36 @@ public class OWSLinkPreview: MTLModel {
|
|||
// <meta property="og:image" content="https://i.ytimg.com/vi/tP-Ipsat90c/maxresdefault.jpg">
|
||||
private class func parse(linkData: Data,
|
||||
linkUrlString: String,
|
||||
completion: @escaping (OWSLinkPreviewInfo?) -> Void) {
|
||||
completion: @escaping (OWSLinkPreviewDraft?) -> Void) {
|
||||
guard let linkText = String(bytes: linkData, encoding: .utf8) else {
|
||||
owsFailDebug("Could not parse link text.")
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
Logger.verbose("linkText: \(linkText)")
|
||||
|
||||
let title = NSRegularExpression.parseFirstMatch(pattern: "<meta property=\"og:title\" content=\"([^\"]+)\">", text: linkText)
|
||||
var title: String?
|
||||
if let rawTitle = NSRegularExpression.parseFirstMatch(pattern: "<meta property=\"og:title\" content=\"([^\"]+)\">", text: linkText) {
|
||||
let normalizedTitle = OWSLinkPreview.normalizeTitle(title: rawTitle)
|
||||
if normalizedTitle.count > 0 {
|
||||
title = normalizedTitle
|
||||
}
|
||||
}
|
||||
|
||||
Logger.verbose("title: \(String(describing: title))")
|
||||
|
||||
guard let imageUrlString = NSRegularExpression.parseFirstMatch(pattern: "<meta property=\"og:image\" content=\"([^\"]+)\">", text: linkText) else {
|
||||
return completion(OWSLinkPreviewInfo(urlString: linkUrlString, title: title))
|
||||
return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title))
|
||||
}
|
||||
Logger.verbose("imageUrlString: \(imageUrlString)")
|
||||
guard let imageUrl = URL(string: imageUrlString) else {
|
||||
Logger.error("Could not parse image URL.")
|
||||
return completion(OWSLinkPreviewInfo(urlString: linkUrlString, title: title))
|
||||
return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title))
|
||||
}
|
||||
let imageFilename = imageUrl.lastPathComponent
|
||||
let imageFileExtension = (imageFilename as NSString).pathExtension.lowercased()
|
||||
guard let imageMimeType = MIMETypeUtil.mimeType(forFileExtension: imageFileExtension) else {
|
||||
Logger.error("Image URL has unknown content type: \(imageFileExtension).")
|
||||
return completion(OWSLinkPreviewInfo(urlString: linkUrlString, title: title))
|
||||
return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title))
|
||||
}
|
||||
let kValidMimeTypes = [
|
||||
OWSMimeTypeImagePng,
|
||||
|
@ -479,21 +545,21 @@ public class OWSLinkPreview: MTLModel {
|
|||
]
|
||||
guard kValidMimeTypes.contains(imageMimeType) else {
|
||||
Logger.error("Image URL has invalid content type: \(imageMimeType).")
|
||||
return completion(OWSLinkPreviewInfo(urlString: linkUrlString, title: title))
|
||||
return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title))
|
||||
}
|
||||
|
||||
downloadContents(ofUrl: imageUrlString,
|
||||
completion: { (imageData) in
|
||||
guard let imageData = imageData else {
|
||||
Logger.error("Could not download image.")
|
||||
return completion(OWSLinkPreviewInfo(urlString: linkUrlString, title: title))
|
||||
return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title))
|
||||
}
|
||||
let imageFilePath = OWSFileSystem.temporaryFilePath(withFileExtension: imageFileExtension)
|
||||
do {
|
||||
try imageData.write(to: NSURL.fileURL(withPath: imageFilePath), options: .atomicWrite)
|
||||
} catch let error as NSError {
|
||||
owsFailDebug("file write failed: \(imageFilePath), \(error)")
|
||||
return completion(OWSLinkPreviewInfo(urlString: linkUrlString, title: title))
|
||||
return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title))
|
||||
}
|
||||
// NOTE: imageSize(forFilePath:...) will call ows_isValidImage(...).
|
||||
let imageSize = NSData.imageSize(forFilePath: imageFilePath, mimeType: imageMimeType)
|
||||
|
@ -503,11 +569,11 @@ public class OWSLinkPreview: MTLModel {
|
|||
imageSize.width < kMaxImageSize,
|
||||
imageSize.height < kMaxImageSize else {
|
||||
Logger.error("Image has invalid size: \(imageSize).")
|
||||
return completion(OWSLinkPreviewInfo(urlString: linkUrlString, title: title))
|
||||
return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title))
|
||||
}
|
||||
|
||||
let linkPreviewInfo = OWSLinkPreviewInfo(urlString: linkUrlString, title: title, imageFilePath: imageFilePath)
|
||||
completion(linkPreviewInfo)
|
||||
let linkPreviewDraft = OWSLinkPreviewDraft(urlString: linkUrlString, title: title, imageFilePath: imageFilePath)
|
||||
completion(linkPreviewDraft)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -989,7 +989,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt
|
|||
if (error || !previewProto) {
|
||||
OWSFailDebug(@"Could not build link preview protobuf: %@.", error);
|
||||
} else {
|
||||
[builder setPreview:previewProto];
|
||||
[builder addPreview:previewProto];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1437,55 +1437,55 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[incomingMessage markAsReadAtTimestamp:envelope.timestamp sendReadReceipt:NO transaction:transaction];
|
||||
}
|
||||
|
||||
TSQuotedMessage *_Nullable quotedMessage = incomingMessage.quotedMessage;
|
||||
if (quotedMessage && quotedMessage.thumbnailAttachmentPointerId) {
|
||||
// We weren't able to derive a local thumbnail, so we'll fetch the referenced attachment.
|
||||
TSAttachmentPointer *attachmentPointer =
|
||||
[TSAttachmentPointer fetchObjectWithUniqueID:quotedMessage.thumbnailAttachmentPointerId
|
||||
transaction:transaction];
|
||||
|
||||
if ([attachmentPointer isKindOfClass:[TSAttachmentPointer class]]) {
|
||||
OWSLogDebug(@"downloading thumbnail for message: %lu", (unsigned long)incomingMessage.timestamp);
|
||||
[self.attachmentDownloads downloadAttachmentPointer:attachmentPointer
|
||||
success:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
||||
OWSAssertDebug(attachmentStreams.count == 1);
|
||||
TSAttachmentStream *attachmentStream = attachmentStreams.firstObject;
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[incomingMessage setQuotedMessageThumbnailAttachmentStream:attachmentStream];
|
||||
[incomingMessage saveWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
OWSLogWarn(@"failed to fetch thumbnail for message: %lu with error: %@",
|
||||
(unsigned long)incomingMessage.timestamp,
|
||||
error);
|
||||
}];
|
||||
}
|
||||
NSMutableArray<NSString *> *otherAttachmentIds = [NSMutableArray new];
|
||||
if (incomingMessage.quotedMessage.thumbnailAttachmentPointerId.length > 0) {
|
||||
[otherAttachmentIds addObject:incomingMessage.quotedMessage.thumbnailAttachmentPointerId];
|
||||
}
|
||||
|
||||
OWSContact *_Nullable contact = incomingMessage.contactShare;
|
||||
if (contact && contact.avatarAttachmentId) {
|
||||
TSAttachmentPointer *attachmentPointer =
|
||||
[TSAttachmentPointer fetchObjectWithUniqueID:contact.avatarAttachmentId transaction:transaction];
|
||||
if (incomingMessage.contactShare.avatarAttachmentId.length > 0) {
|
||||
[otherAttachmentIds addObject:incomingMessage.contactShare.avatarAttachmentId];
|
||||
}
|
||||
if (incomingMessage.linkPreview.imageAttachmentId.length > 0) {
|
||||
[otherAttachmentIds addObject:incomingMessage.linkPreview.imageAttachmentId];
|
||||
}
|
||||
for (NSString *attachmentId in otherAttachmentIds) {
|
||||
TSAttachmentPointer *_Nullable attachmentPointer =
|
||||
[TSAttachmentPointer fetchObjectWithUniqueID:attachmentId transaction:transaction];
|
||||
|
||||
if (![attachmentPointer isKindOfClass:[TSAttachmentPointer class]]) {
|
||||
OWSFailDebug(@"avatar attachmentPointer was unexpectedly nil");
|
||||
} else {
|
||||
OWSLogDebug(@"downloading contact avatar for message: %lu", (unsigned long)incomingMessage.timestamp);
|
||||
|
||||
[self.attachmentDownloads downloadAttachmentPointer:attachmentPointer
|
||||
success:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[incomingMessage touchWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
OWSLogWarn(@"failed to fetch contact avatar for message: %lu with error: %@",
|
||||
(unsigned long)incomingMessage.timestamp,
|
||||
error);
|
||||
}];
|
||||
OWSFailDebug(@"Missing attachment pointer.");
|
||||
continue;
|
||||
}
|
||||
|
||||
OWSLogDebug(@"Downloading attachment for message: %lu", (unsigned long)incomingMessage.timestamp);
|
||||
|
||||
// Use a separate download for each attachment so that:
|
||||
//
|
||||
// * We update the message as each comes in.
|
||||
// * Failures don't interfere with successes.
|
||||
[self.attachmentDownloads downloadAttachmentPointer:attachmentPointer
|
||||
success:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
TSAttachmentStream *_Nullable attachmentStream = attachmentStreams.firstObject;
|
||||
OWSAssertDebug(attachmentStream);
|
||||
if (attachmentStream && incomingMessage.quotedMessage.thumbnailAttachmentPointerId.length > 0 &&
|
||||
[attachmentStream.uniqueId
|
||||
isEqualToString:incomingMessage.quotedMessage.thumbnailAttachmentPointerId]) {
|
||||
[incomingMessage setQuotedMessageThumbnailAttachmentStream:attachmentStream];
|
||||
[incomingMessage saveWithTransaction:transaction];
|
||||
} else {
|
||||
// We touch the message to trigger redraw of any views displaying it,
|
||||
// since the attachment might be a contact avatar, etc.
|
||||
[incomingMessage touchWithTransaction:transaction];
|
||||
}
|
||||
}];
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
OWSLogWarn(@"failed to download attachment for message: %lu with error: %@",
|
||||
(unsigned long)incomingMessage.timestamp,
|
||||
error);
|
||||
}];
|
||||
}
|
||||
|
||||
// In case we already have a read receipt for this new message (this happens sometimes).
|
||||
[OWSReadReceiptManager.sharedManager applyEarlyReadReceiptsForIncomingMessage:incomingMessage
|
||||
transaction:transaction];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DataSource.h"
|
||||
|
@ -103,10 +103,8 @@ NS_SWIFT_NAME(MessageSender)
|
|||
@interface OutgoingMessagePreparer : NSObject
|
||||
|
||||
/// Persists all necessary data to disk before sending, e.g. generate thumbnails
|
||||
+ (void)prepareMessageForSending:(TSOutgoingMessage *)message
|
||||
quotedThumbnailAttachments:(NSArray<TSAttachmentStream *> **)outQuotedThumbnailAttachments
|
||||
contactShareAvatarAttachment:(TSAttachmentStream **)outContactShareAvatarAttachment
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
+ (NSArray<NSString *> *)prepareMessageForSending:(TSOutgoingMessage *)message
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
/// Writes attachment to disk and applies original filename to message attributes
|
||||
+ (void)prepareAttachments:(NSArray<OWSOutgoingAttachmentInfo *> *)attachmentInfos
|
||||
|
|
|
@ -355,9 +355,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
}
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
|
||||
__block NSArray<TSAttachmentStream *> *quotedThumbnailAttachments = @[];
|
||||
__block TSAttachmentStream *_Nullable contactShareAvatarAttachment;
|
||||
NSMutableArray<NSString *> *allAttachmentIds = [NSMutableArray new];
|
||||
|
||||
// This method will use a read/write transaction. This transaction
|
||||
// will block until any open read/write transactions are complete.
|
||||
|
@ -372,10 +370,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
// So we're using YDB behavior to ensure this invariant, which is a bit
|
||||
// unorthodox.
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[OutgoingMessagePreparer prepareMessageForSending:message
|
||||
quotedThumbnailAttachments:"edThumbnailAttachments
|
||||
contactShareAvatarAttachment:&contactShareAvatarAttachment
|
||||
transaction:transaction];
|
||||
[allAttachmentIds
|
||||
addObjectsFromArray:[OutgoingMessagePreparer prepareMessageForSending:message transaction:transaction]];
|
||||
}];
|
||||
|
||||
NSOperationQueue *sendingQueue = [self sendingQueueForMessage:message];
|
||||
|
@ -386,41 +382,14 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
success:successHandler
|
||||
failure:failureHandler];
|
||||
|
||||
// TODO: de-dupe attachment enqueue logic.
|
||||
for (NSString *attachmentId in message.attachmentIds) {
|
||||
for (NSString *attachmentId in allAttachmentIds) {
|
||||
OWSUploadOperation *uploadAttachmentOperation =
|
||||
[[OWSUploadOperation alloc] initWithAttachmentId:attachmentId dbConnection:self.dbConnection];
|
||||
// TODO: put attachment uploads on a (low priority) concurrent queue
|
||||
[sendMessageOperation addDependency:uploadAttachmentOperation];
|
||||
[sendingQueue addOperation:uploadAttachmentOperation];
|
||||
}
|
||||
|
||||
// Though we currently only ever expect at most one thumbnail, the proto data model
|
||||
// suggests this could change. The logic is intended to work with multiple, but
|
||||
// if we ever actually want to send multiple, we should do more testing.
|
||||
OWSAssertDebug(quotedThumbnailAttachments.count <= 1);
|
||||
for (TSAttachmentStream *thumbnailAttachment in quotedThumbnailAttachments) {
|
||||
OWSAssertDebug(message.quotedMessage);
|
||||
|
||||
OWSUploadOperation *uploadQuoteThumbnailOperation =
|
||||
[[OWSUploadOperation alloc] initWithAttachmentId:thumbnailAttachment.uniqueId
|
||||
dbConnection:self.dbConnection];
|
||||
|
||||
// TODO put attachment uploads on a (lowly) concurrent queue
|
||||
[sendMessageOperation addDependency:uploadQuoteThumbnailOperation];
|
||||
[sendingQueue addOperation:uploadQuoteThumbnailOperation];
|
||||
}
|
||||
|
||||
if (contactShareAvatarAttachment != nil) {
|
||||
OWSAssertDebug(message.contactShare);
|
||||
OWSUploadOperation *uploadAvatarOperation =
|
||||
[[OWSUploadOperation alloc] initWithAttachmentId:contactShareAvatarAttachment.uniqueId
|
||||
dbConnection:self.dbConnection];
|
||||
|
||||
// TODO put attachment uploads on a (lowly) concurrent queue
|
||||
[sendMessageOperation addDependency:uploadAvatarOperation];
|
||||
[sendingQueue addOperation:uploadAvatarOperation];
|
||||
}
|
||||
|
||||
[sendingQueue addOperation:sendMessageOperation];
|
||||
});
|
||||
}
|
||||
|
@ -1838,22 +1807,45 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
|
||||
#pragma mark -
|
||||
|
||||
+ (void)prepareMessageForSending:(TSOutgoingMessage *)message
|
||||
quotedThumbnailAttachments:(NSArray<TSAttachmentStream *> **)outQuotedThumbnailAttachments
|
||||
contactShareAvatarAttachment:(TSAttachmentStream *_Nullable *)outContactShareAvatarAttachment
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
+ (NSArray<NSString *> *)prepareMessageForSending:(TSOutgoingMessage *)message
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssertDebug(message);
|
||||
OWSAssertDebug(transaction);
|
||||
|
||||
NSMutableArray<NSString *> *attachmentIds = [NSMutableArray new];
|
||||
|
||||
if (message.attachmentIds) {
|
||||
[attachmentIds addObjectsFromArray:message.attachmentIds];
|
||||
}
|
||||
|
||||
if (message.quotedMessage) {
|
||||
*outQuotedThumbnailAttachments =
|
||||
// Though we currently only ever expect at most one thumbnail, the proto data model
|
||||
// suggests this could change. The logic is intended to work with multiple, but
|
||||
// if we ever actually want to send multiple, we should do more testing.
|
||||
NSArray<TSAttachmentStream *> *quotedThumbnailAttachments =
|
||||
[message.quotedMessage createThumbnailAttachmentsIfNecessaryWithTransaction:transaction];
|
||||
for (TSAttachmentStream *attachment in quotedThumbnailAttachments) {
|
||||
[attachmentIds addObject:attachment.uniqueId];
|
||||
}
|
||||
}
|
||||
|
||||
if (message.contactShare.avatarAttachmentId != nil) {
|
||||
TSAttachment *avatarAttachment = [message.contactShare avatarAttachmentWithTransaction:transaction];
|
||||
if ([avatarAttachment isKindOfClass:[TSAttachmentStream class]]) {
|
||||
*outContactShareAvatarAttachment = (TSAttachmentStream *)avatarAttachment;
|
||||
TSAttachment *attachment = [message.contactShare avatarAttachmentWithTransaction:transaction];
|
||||
if ([attachment isKindOfClass:[TSAttachmentStream class]]) {
|
||||
[attachmentIds addObject:attachment.uniqueId];
|
||||
} else {
|
||||
OWSFailDebug(@"unexpected avatarAttachment: %@", avatarAttachment);
|
||||
OWSFailDebug(@"unexpected avatarAttachment: %@", attachment);
|
||||
}
|
||||
}
|
||||
|
||||
if (message.linkPreview.imageAttachmentId != nil) {
|
||||
TSAttachment *attachment =
|
||||
[TSAttachment fetchObjectWithUniqueID:message.linkPreview.imageAttachmentId transaction:transaction];
|
||||
if ([attachment isKindOfClass:[TSAttachmentStream class]]) {
|
||||
[attachmentIds addObject:attachment.uniqueId];
|
||||
} else {
|
||||
OWSFailDebug(@"unexpected attachment: %@", attachment);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1861,6 +1853,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
[message saveWithTransaction:transaction];
|
||||
// When we start a message send, all "failed" recipients should be marked as "sending".
|
||||
[message updateWithMarkingAllUnsentRecipientsAsSendingWithTransaction:transaction];
|
||||
|
||||
return attachmentIds;
|
||||
}
|
||||
|
||||
+ (void)prepareAttachments:(NSArray<OWSOutgoingAttachmentInfo *> *)attachmentInfos
|
||||
|
|
|
@ -2864,9 +2864,7 @@ extension SSKProtoDataMessagePreview.SSKProtoDataMessagePreviewBuilder {
|
|||
builder.setQuote(_value)
|
||||
}
|
||||
builder.setContact(contact)
|
||||
if let _value = preview {
|
||||
builder.setPreview(_value)
|
||||
}
|
||||
builder.setPreview(preview)
|
||||
return builder
|
||||
}
|
||||
|
||||
|
@ -2924,8 +2922,14 @@ extension SSKProtoDataMessagePreview.SSKProtoDataMessagePreviewBuilder {
|
|||
proto.contact = wrappedItems.map { $0.proto }
|
||||
}
|
||||
|
||||
@objc public func setPreview(_ valueParam: SSKProtoDataMessagePreview) {
|
||||
proto.preview = valueParam.proto
|
||||
@objc public func addPreview(_ valueParam: SSKProtoDataMessagePreview) {
|
||||
var items = proto.preview
|
||||
items.append(valueParam.proto)
|
||||
proto.preview = items
|
||||
}
|
||||
|
||||
@objc public func setPreview(_ wrappedItems: [SSKProtoDataMessagePreview]) {
|
||||
proto.preview = wrappedItems.map { $0.proto }
|
||||
}
|
||||
|
||||
@objc public func build() throws -> SSKProtoDataMessage {
|
||||
|
@ -2947,7 +2951,7 @@ extension SSKProtoDataMessagePreview.SSKProtoDataMessagePreviewBuilder {
|
|||
|
||||
@objc public let contact: [SSKProtoDataMessageContact]
|
||||
|
||||
@objc public let preview: SSKProtoDataMessagePreview?
|
||||
@objc public let preview: [SSKProtoDataMessagePreview]
|
||||
|
||||
@objc public var body: String? {
|
||||
guard proto.hasBody else {
|
||||
|
@ -2995,7 +2999,7 @@ extension SSKProtoDataMessagePreview.SSKProtoDataMessagePreviewBuilder {
|
|||
group: SSKProtoGroupContext?,
|
||||
quote: SSKProtoDataMessageQuote?,
|
||||
contact: [SSKProtoDataMessageContact],
|
||||
preview: SSKProtoDataMessagePreview?) {
|
||||
preview: [SSKProtoDataMessagePreview]) {
|
||||
self.proto = proto
|
||||
self.attachments = attachments
|
||||
self.group = group
|
||||
|
@ -3031,10 +3035,8 @@ extension SSKProtoDataMessagePreview.SSKProtoDataMessagePreviewBuilder {
|
|||
var contact: [SSKProtoDataMessageContact] = []
|
||||
contact = try proto.contact.map { try SSKProtoDataMessageContact.parseProto($0) }
|
||||
|
||||
var preview: SSKProtoDataMessagePreview? = nil
|
||||
if proto.hasPreview {
|
||||
preview = try SSKProtoDataMessagePreview.parseProto(proto.preview)
|
||||
}
|
||||
var preview: [SSKProtoDataMessagePreview] = []
|
||||
preview = try proto.preview.map { try SSKProtoDataMessagePreview.parseProto($0) }
|
||||
|
||||
// MARK: - Begin Validation Logic for SSKProtoDataMessage -
|
||||
|
||||
|
|
|
@ -634,14 +634,10 @@ struct SignalServiceProtos_DataMessage {
|
|||
set {_uniqueStorage()._contact = newValue}
|
||||
}
|
||||
|
||||
var preview: SignalServiceProtos_DataMessage.Preview {
|
||||
get {return _storage._preview ?? SignalServiceProtos_DataMessage.Preview()}
|
||||
var preview: [SignalServiceProtos_DataMessage.Preview] {
|
||||
get {return _storage._preview}
|
||||
set {_uniqueStorage()._preview = newValue}
|
||||
}
|
||||
/// Returns true if `preview` has been explicitly set.
|
||||
var hasPreview: Bool {return _storage._preview != nil}
|
||||
/// Clears the value of `preview`. Subsequent reads from it will return its default value.
|
||||
mutating func clearPreview() {_uniqueStorage()._preview = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
|
@ -2834,7 +2830,7 @@ extension SignalServiceProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf.
|
|||
var _timestamp: UInt64? = nil
|
||||
var _quote: SignalServiceProtos_DataMessage.Quote? = nil
|
||||
var _contact: [SignalServiceProtos_DataMessage.Contact] = []
|
||||
var _preview: SignalServiceProtos_DataMessage.Preview? = nil
|
||||
var _preview: [SignalServiceProtos_DataMessage.Preview] = []
|
||||
|
||||
static let defaultInstance = _StorageClass()
|
||||
|
||||
|
@ -2875,7 +2871,7 @@ extension SignalServiceProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf.
|
|||
case 7: try decoder.decodeSingularUInt64Field(value: &_storage._timestamp)
|
||||
case 8: try decoder.decodeSingularMessageField(value: &_storage._quote)
|
||||
case 9: try decoder.decodeRepeatedMessageField(value: &_storage._contact)
|
||||
case 10: try decoder.decodeSingularMessageField(value: &_storage._preview)
|
||||
case 10: try decoder.decodeRepeatedMessageField(value: &_storage._preview)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -2911,8 +2907,8 @@ extension SignalServiceProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf.
|
|||
if !_storage._contact.isEmpty {
|
||||
try visitor.visitRepeatedMessageField(value: _storage._contact, fieldNumber: 9)
|
||||
}
|
||||
if let v = _storage._preview {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 10)
|
||||
if !_storage._preview.isEmpty {
|
||||
try visitor.visitRepeatedMessageField(value: _storage._preview, fieldNumber: 10)
|
||||
}
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
|
|
Loading…
Reference in a new issue