Send 'sent update' sync messages.

pull/2/head
Matthew Chen 6 years ago
parent 6ce84e7f9b
commit 4f19d03bdc

@ -19,8 +19,6 @@ NS_ASSUME_NONNULL_BEGIN
NSArray<TSAttachmentStream *> *attachmentStreams))attachmentHandler NSArray<TSAttachmentStream *> *attachmentStreams))attachmentHandler
transaction:(YapDatabaseReadWriteTransaction *)transaction; transaction:(YapDatabaseReadWriteTransaction *)transaction;
+ (BOOL)areSentUpdatesEnabled;
+ (void)processSentUpdateTranscript:(SSKProtoSyncMessageSentUpdate *)sentUpdate + (void)processSentUpdateTranscript:(SSKProtoSyncMessageSentUpdate *)sentUpdate
transaction:(YapDatabaseReadWriteTransaction *)transaction; transaction:(YapDatabaseReadWriteTransaction *)transaction;

@ -67,13 +67,6 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssertDebug(transcript); OWSAssertDebug(transcript);
OWSAssertDebug(transaction); OWSAssertDebug(transaction);
if (self.dataMessage.group) {
_thread = [TSGroupThread getOrCreateThreadWithGroupId:_dataMessage.group.id transaction:transaction];
} else {
_thread = [TSContactThread getOrCreateThreadWithContactId:_recipientId transaction:transaction];
}
OWSLogInfo(@"Recording transcript in thread: %@ timestamp: %llu", transcript.thread.uniqueId, transcript.timestamp); OWSLogInfo(@"Recording transcript in thread: %@ timestamp: %llu", transcript.thread.uniqueId, transcript.timestamp);
if (transcript.isEndSessionMessage) { if (transcript.isEndSessionMessage) {
@ -183,18 +176,13 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - #pragma mark -
+ (BOOL)areSentUpdatesEnabled
{
return NO;
}
+ (void)processSentUpdateTranscript:(SSKProtoSyncMessageSentUpdate *)sentUpdate + (void)processSentUpdateTranscript:(SSKProtoSyncMessageSentUpdate *)sentUpdate
transaction:(YapDatabaseReadWriteTransaction *)transaction transaction:(YapDatabaseReadWriteTransaction *)transaction
{ {
OWSAssertDebug(sentUpdate); OWSAssertDebug(sentUpdate);
OWSAssertDebug(transaction); OWSAssertDebug(transaction);
if (!self.areSentUpdatesEnabled) { if (!AreSentUpdatesEnabled()) {
OWSFailDebug(@"Ignoring 'sent update' transcript; disabled."); OWSFailDebug(@"Ignoring 'sent update' transcript; disabled.");
return; return;
} }

@ -0,0 +1,25 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "OWSOutgoingSyncMessage.h"
NS_ASSUME_NONNULL_BEGIN
@class TSOutgoingMessage;
/**
* Notifies your other registered devices (if you have any) that you've sent a message.
* This way the message you just sent can appear on all your devices.
*/
@interface OWSOutgoingSentUpdateMessageTranscript : OWSOutgoingSyncMessage
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithOutgoingMessage:(TSOutgoingMessage *)message
transaction:(YapDatabaseReadTransaction *)transaction NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,100 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "OWSOutgoingSentUpdateMessageTranscript.h"
#import "TSGroupThread.h"
#import "TSOutgoingMessage.h"
#import "TSThread.h"
#import <SignalServiceKit/SignalServiceKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN
@interface TSOutgoingMessage (OWSOutgoingSentMessageTranscript)
/**
* Normally this is private, but we need to embed this
* data structure within our own.
*
* recipientId is nil when building "sent" sync messages for messages
* sent to groups.
*/
- (nullable SSKProtoDataMessage *)buildDataMessage:(NSString *_Nullable)recipientId;
@end
@interface OWSOutgoingSentUpdateMessageTranscript ()
@property (nonatomic, readonly) TSOutgoingMessage *message;
@property (nonatomic, readonly) TSGroupThread *groupThread;
@end
@implementation OWSOutgoingSentUpdateMessageTranscript
- (instancetype)initWithOutgoingMessage:(TSOutgoingMessage *)message
transaction:(YapDatabaseReadTransaction *)transaction
{
self = [super init];
if (!self) {
return self;
}
_message = message;
_groupThread = (TSGroupThread *)[message threadWithTransaction:transaction];
return self;
}
- (nullable instancetype)initWithCoder:(NSCoder *)coder
{
return [super initWithCoder:coder];
}
- (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilder
{
SSKProtoSyncMessageSentUpdateBuilder *sentBuilder =
[SSKProtoSyncMessageSentUpdate builderWithGroupID:self.groupThread.groupModel.groupId
timestamp:self.message.timestamp];
for (NSString *recipientId in self.message.sentRecipientIds) {
TSOutgoingMessageRecipientState *_Nullable recipientState =
[self.message recipientStateForRecipientId:recipientId];
if (!recipientState) {
OWSFailDebug(@"missing recipient state for: %@", recipientId);
continue;
}
if (recipientState.state != OWSOutgoingMessageRecipientStateSent) {
OWSFailDebug(@"unexpected recipient state for: %@", recipientId);
continue;
}
NSError *error;
SSKProtoSyncMessageSentUpdateUnidentifiedDeliveryStatusBuilder *statusBuilder =
[SSKProtoSyncMessageSentUpdateUnidentifiedDeliveryStatus builderWithDestination:recipientId];
[statusBuilder setUnidentified:recipientState.wasSentByUD];
SSKProtoSyncMessageSentUpdateUnidentifiedDeliveryStatus *_Nullable status =
[statusBuilder buildAndReturnError:&error];
if (error || !status) {
OWSFailDebug(@"Couldn't build UD status proto: %@", error);
continue;
}
[sentBuilder addUnidentifiedStatus:status];
}
NSError *error;
SSKProtoSyncMessageSentUpdate *_Nullable sentUpdateProto = [sentBuilder buildAndReturnError:&error];
if (error || !sentUpdateProto) {
OWSFailDebug(@"could not build protobuf: %@", error);
return nil;
}
SSKProtoSyncMessageBuilder *syncMessageBuilder = [SSKProtoSyncMessage builder];
[syncMessageBuilder setSentUpdate:sentUpdateProto];
return syncMessageBuilder;
}
@end
NS_ASSUME_NONNULL_END

@ -6,6 +6,11 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
// Feature flag.
//
// TODO: Remove.
BOOL AreSentUpdatesEnabled(void);
typedef NS_ENUM(NSInteger, TSOutgoingMessageState) { typedef NS_ENUM(NSInteger, TSOutgoingMessageState) {
// The message is either: // The message is either:
// a) Enqueued for sending. // a) Enqueued for sending.

@ -23,6 +23,11 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
BOOL AreSentUpdatesEnabled(void)
{
return NO;
}
NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRecipientAll"; NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRecipientAll";
NSString *NSStringForOutgoingMessageState(TSOutgoingMessageState value) NSString *NSStringForOutgoingMessageState(TSOutgoingMessageState value)
@ -1104,7 +1109,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt
- (BOOL)shouldSyncTranscript - (BOOL)shouldSyncTranscript
{ {
return !self.hasSyncedTranscript; return YES;
} }
- (NSString *)statusDescription - (NSString *)statusDescription

@ -18,6 +18,7 @@
#import "OWSMessageServiceParams.h" #import "OWSMessageServiceParams.h"
#import "OWSOperation.h" #import "OWSOperation.h"
#import "OWSOutgoingSentMessageTranscript.h" #import "OWSOutgoingSentMessageTranscript.h"
#import "OWSOutgoingSentUpdateMessageTranscript.h"
#import "OWSOutgoingSyncMessage.h" #import "OWSOutgoingSyncMessage.h"
#import "OWSPrimaryStorage+PreKeyStore.h" #import "OWSPrimaryStorage+PreKeyStore.h"
#import "OWSPrimaryStorage+SignedPreKeyStore.h" #import "OWSPrimaryStorage+SignedPreKeyStore.h"
@ -1391,20 +1392,27 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
return success(); return success();
} }
[self if (message.hasSyncedTranscript) {
sendSyncTranscriptForMessage:message if (!AreSentUpdatesEnabled()) {
success:^{ return success();
// TODO: We might send to a recipient, then to another recipient on retry. }
// To ensure desktop receives all "delivery status" info, we might [self sendSyncUpdateTranscriptForMessage:message
// want to send a transcript after every send that reaches _any_ success:^{
// new recipients. success();
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { }
[message updateWithHasSyncedTranscript:YES transaction:transaction]; failure:failure];
}]; } else {
[self sendSyncTranscriptForMessage:message
success(); success:^{
} [self.dbConnection
failure:failure]; readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[message updateWithHasSyncedTranscript:YES transaction:transaction];
}];
success();
}
failure:failure];
}
} }
- (void)sendSyncTranscriptForMessage:(TSOutgoingMessage *)message - (void)sendSyncTranscriptForMessage:(TSOutgoingMessage *)message
@ -1439,6 +1447,50 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[self sendMessageToRecipient:messageSend]; [self sendMessageToRecipient:messageSend];
} }
- (void)sendSyncUpdateTranscriptForMessage:(TSOutgoingMessage *)message
success:(void (^)(void))success
failure:(RetryableFailureHandler)failure
{
NSString *recipientId = self.tsAccountManager.localNumber;
__block OWSOutgoingSentUpdateMessageTranscript *transcript;
__block BOOL isGroupThread = NO;
__block SignalRecipient *recipient;
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
isGroupThread = message.thread.isGroupThread;
if (isGroupThread) {
recipient = [SignalRecipient markRecipientAsRegisteredAndGet:recipientId transaction:transaction];
transcript = [[OWSOutgoingSentUpdateMessageTranscript alloc] initWithOutgoingMessage:message
transaction:transaction];
}
}];
if (!isGroupThread) {
// We only send "sent update" transcripts for group messages.
return success();
}
OWSMessageSend *messageSend = [[OWSMessageSend alloc] initWithMessage:transcript
thread:message.thread
recipient:recipient
senderCertificate:nil
udAccess:nil
localNumber:self.tsAccountManager.localNumber
success:^{
OWSLogInfo(@"Successfully sent 'sent update' sync transcript.");
success();
}
failure:^(NSError *error) {
OWSLogInfo(
@"Failed to send 'sent update' sync transcript: %@ (isRetryable: %d)", error, [error isRetryable]);
failure(error);
}];
[self sendMessageToRecipient:messageSend];
}
- (NSArray<NSDictionary *> *)throws_deviceMessagesForMessageSend:(OWSMessageSend *)messageSend - (NSArray<NSDictionary *> *)throws_deviceMessagesForMessageSend:(OWSMessageSend *)messageSend
{ {
OWSAssertDebug(messageSend.message); OWSAssertDebug(messageSend.message);

Loading…
Cancel
Save