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
transaction:(YapDatabaseReadWriteTransaction *)transaction;
+ (BOOL)areSentUpdatesEnabled;
+ (void)processSentUpdateTranscript:(SSKProtoSyncMessageSentUpdate *)sentUpdate
transaction:(YapDatabaseReadWriteTransaction *)transaction;

@ -67,13 +67,6 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssertDebug(transcript);
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);
if (transcript.isEndSessionMessage) {
@ -183,18 +176,13 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark -
+ (BOOL)areSentUpdatesEnabled
{
return NO;
}
+ (void)processSentUpdateTranscript:(SSKProtoSyncMessageSentUpdate *)sentUpdate
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssertDebug(sentUpdate);
OWSAssertDebug(transaction);
if (!self.areSentUpdatesEnabled) {
if (!AreSentUpdatesEnabled()) {
OWSFailDebug(@"Ignoring 'sent update' transcript; disabled.");
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
// Feature flag.
//
// TODO: Remove.
BOOL AreSentUpdatesEnabled(void);
typedef NS_ENUM(NSInteger, TSOutgoingMessageState) {
// The message is either:
// a) Enqueued for sending.

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

@ -18,6 +18,7 @@
#import "OWSMessageServiceParams.h"
#import "OWSOperation.h"
#import "OWSOutgoingSentMessageTranscript.h"
#import "OWSOutgoingSentUpdateMessageTranscript.h"
#import "OWSOutgoingSyncMessage.h"
#import "OWSPrimaryStorage+PreKeyStore.h"
#import "OWSPrimaryStorage+SignedPreKeyStore.h"
@ -1391,20 +1392,27 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
return success();
}
[self
sendSyncTranscriptForMessage:message
success:^{
// TODO: We might send to a recipient, then to another recipient on retry.
// To ensure desktop receives all "delivery status" info, we might
// want to send a transcript after every send that reaches _any_
// new recipients.
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[message updateWithHasSyncedTranscript:YES transaction:transaction];
}];
success();
}
failure:failure];
if (message.hasSyncedTranscript) {
if (!AreSentUpdatesEnabled()) {
return success();
}
[self sendSyncUpdateTranscriptForMessage:message
success:^{
success();
}
failure:failure];
} else {
[self sendSyncTranscriptForMessage:message
success:^{
[self.dbConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[message updateWithHasSyncedTranscript:YES transaction:transaction];
}];
success();
}
failure:failure];
}
}
- (void)sendSyncTranscriptForMessage:(TSOutgoingMessage *)message
@ -1439,6 +1447,50 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[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
{
OWSAssertDebug(messageSend.message);

Loading…
Cancel
Save