Fix minor logic issue & document friend request handling

pull/16/head
Niels Andriesse 6 years ago
parent 7faa9d333c
commit 4d94346959

@ -31,17 +31,17 @@ extern ConversationColorName const kConversationColorName_Default;
// Loki: Friend request state // Loki: Friend request state
typedef NS_ENUM(NSInteger, TSThreadFriendRequestStatus) { typedef NS_ENUM(NSInteger, TSThreadFriendRequestStatus) {
// New conversation, no messages sent or received /// New conversation, no messages sent or received
TSThreadFriendRequestStatusNone, TSThreadFriendRequestStatusNone,
// This state is used to lock the input early while sending /// This state is used to lock the input early while sending
TSThreadFriendRequestStatusPendingSend, TSThreadFriendRequestStatusRequestSending,
// Friend request sent, awaiting response /// Friend request sent, awaiting response
TSThreadFriendRequestStatusRequestSent, TSThreadFriendRequestStatusRequestSent,
// Friend request received, awaiting user input /// Friend request received, awaiting user input
TSThreadFriendRequestStatusRequestReceived, TSThreadFriendRequestStatusRequestReceived,
// We are friends with the user of this thread /// We are friends with the user of this thread
TSThreadFriendRequestStatusFriends, TSThreadFriendRequestStatusFriends,
// Friend request sent but it timed out (user didn't accept within x time) /// Friend request sent but it timed out (user didn't accept within x time)
TSThreadFriendRequestStatusRequestExpired TSThreadFriendRequestStatusRequestExpired
}; };
@ -54,13 +54,15 @@ typedef NS_ENUM(NSInteger, TSThreadFriendRequestStatus) {
@property (nonatomic, readonly) NSDate *creationDate; @property (nonatomic, readonly) NSDate *creationDate;
@property (nonatomic, readonly) BOOL isArchivedByLegacyTimestampForSorting; @property (nonatomic, readonly) BOOL isArchivedByLegacyTimestampForSorting;
// Loki friend request handling // Loki friend request handling
// ========
@property (nonatomic) TSThreadFriendRequestStatus friendRequestStatus; @property (nonatomic) TSThreadFriendRequestStatus friendRequestStatus;
/// Shorthand for checking that `friendRequestStatus` is `TSThreadFriendRequestStatusPendingSend`, `TSThreadFriendRequestStatusRequestSent` /// Shorthand for checking that `friendRequestStatus` is `TSThreadFriendRequestStatusRequestSending`, `TSThreadFriendRequestStatusRequestSent`
/// or `TSThreadFriendRequestStatusRequestReceived`. /// or `TSThreadFriendRequestStatusRequestReceived`.
@property (nonatomic, readonly) BOOL hasPendingFriendRequest; @property (nonatomic, readonly) BOOL hasPendingFriendRequest;
@property (nonatomic, readonly) BOOL isContactFriend; @property (nonatomic, readonly) BOOL isContactFriend;
@property (nonatomic, readonly) BOOL hasCurrentUserSentFriendRequest; @property (nonatomic, readonly) BOOL hasCurrentUserSentFriendRequest;
@property (nonatomic, readonly) BOOL hasCurrentUserReceivedFriendRequest; @property (nonatomic, readonly) BOOL hasCurrentUserReceivedFriendRequest;
// ========
/** /**
* Whether the object is a group thread or not. * Whether the object is a group thread or not.

@ -710,7 +710,7 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
- (BOOL)hasPendingFriendRequest - (BOOL)hasPendingFriendRequest
{ {
return self.friendRequestStatus == TSThreadFriendRequestStatusPendingSend || self.friendRequestStatus == TSThreadFriendRequestStatusRequestSent return self.friendRequestStatus == TSThreadFriendRequestStatusRequestSending || self.friendRequestStatus == TSThreadFriendRequestStatusRequestSent
|| self.friendRequestStatus == TSThreadFriendRequestStatusRequestReceived; || self.friendRequestStatus == TSThreadFriendRequestStatusRequestReceived;
} }

@ -28,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly, nullable) TSQuotedMessage *quotedMessage; @property (nonatomic, readonly, nullable) TSQuotedMessage *quotedMessage;
@property (nonatomic, readonly, nullable) OWSContact *contactShare; @property (nonatomic, readonly, nullable) OWSContact *contactShare;
@property (nonatomic, readonly, nullable) OWSLinkPreview *linkPreview; @property (nonatomic, readonly, nullable) OWSLinkPreview *linkPreview;
@property (nonatomic) BOOL isFriendRequest; @property (nonatomic) BOOL isFriendRequest; // Loki
- (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE; - (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE;

@ -1446,12 +1446,32 @@ NS_ASSUME_NONNULL_BEGIN
// ======== // ========
if (envelope.type == SSKProtoEnvelopeTypeFriendRequest) { if (envelope.type == SSKProtoEnvelopeTypeFriendRequest) {
if (thread.hasCurrentUserSentFriendRequest) { if (thread.hasCurrentUserSentFriendRequest) {
// This can happen if Alice sent Bob a friend request, Bob declined, but then Bob changed his
// mind and sent a friend request to Alice. In this case we want Alice to auto-accept the request
// and send a friend request accepted message back to Bob. We don't check that sending the
// friend request accepted message succeeded. Even if it doesn't, the thread's current friend
// request status will be set to TSThreadFriendRequestStatusFriends for Alice making it possible
// for Alice to send messages to Bob. When Bob receives a message, his thread's friend request status
// will then be set to TSThreadFriendRequestStatusFriends. If we do check for a successful send
// before updating Alice's thread's friend request status to TSThreadFriendRequestStatusFriends,
// we can end up in a deadlock where both users' threads' friend request statuses are
// TSThreadFriendRequestStatusRequestSent.
[thread setFriendRequestStatus:TSThreadFriendRequestStatusFriends withTransaction:transaction]; [thread setFriendRequestStatus:TSThreadFriendRequestStatusFriends withTransaction:transaction];
} else { // The two lines below are equivalent to calling [ThreadUtil enqueueAcceptFriendRequestMessageInThread:thread]
TSOutgoingMessage *message = [TSOutgoingMessage createEmptyOutgoingMessageInThread:thread];
[self.messageSenderJobQueue addMessage:message transaction:transaction];
} else if (!thread.isContactFriend) {
// Checking that the sender of the message isn't already a friend is necessary because otherwise
// the following situation can occur: Alice and Bob are friends. Bob loses his database and his
// friend request status is reset to TSThreadFriendRequestStatusNone. Bob now sends Alice a friend
// request. Alice's thread's friend request status is reset to
// TSThreadFriendRequestStatusRequestReceived.
[thread setFriendRequestStatus:TSThreadFriendRequestStatusRequestReceived withTransaction:transaction]; [thread setFriendRequestStatus:TSThreadFriendRequestStatusRequestReceived withTransaction:transaction];
incomingMessage.isFriendRequest = YES; // Saved below incomingMessage.isFriendRequest = YES; // Saved below
} }
} else if (!thread.isContactFriend) { } else if (!thread.isContactFriend) {
// If the thread's friend request status is not TSThreadFriendRequestStatusFriends, but we're receiving a message,
// it must be a friend request accepted message. Declining a friend request doesn't send a message.
[thread setFriendRequestStatus:TSThreadFriendRequestStatusFriends withTransaction:transaction]; [thread setFriendRequestStatus:TSThreadFriendRequestStatusFriends withTransaction:transaction];
} }
// ======== // ========

@ -1105,13 +1105,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// Update the state to show that proof of work is being calculated // Update the state to show that proof of work is being calculated
[self setIsCalculatingProofOfWorkForMessage:messageSend]; [self setIsCalculatingProofOfWorkForMessage:messageSend];
// Convert the message to a Loki message and send it using the Loki messaging API // Convert the message to a Loki message and send it using the Loki messaging API
NSDictionary *signalMessage = deviceMessages.firstObject; NSDictionary *signalMessage = deviceMessages.firstObject;
// Update the thread's friend request status if needed // Update the thread's friend request status if needed
NSInteger *messageType = ((NSNumber *)signalMessage[@"type"]).integerValue; NSInteger *messageType = ((NSNumber *)signalMessage[@"type"]).integerValue;
if (messageType == TSFriendRequestMessageType) { if (messageType == TSFriendRequestMessageType) {
[message.thread setFriendRequestStatus:TSThreadFriendRequestStatusPendingSend withTransaction:nil]; [message.thread setFriendRequestStatus:TSThreadFriendRequestStatusRequestSending withTransaction:nil];
[message setIsFriendRequest:YES withTransaction:nil]; [message setIsFriendRequest:YES withTransaction:nil];
} }
BOOL isPoWRequired = YES; // TODO: Base on message type BOOL isPoWRequired = YES; // TODO: Base on message type
@ -1134,10 +1133,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
wasSentByWebsocket:false]; wasSentByWebsocket:false];
}) })
.catchOn(OWSDispatch.sendingQueue, ^(NSError *error) { .catchOn(OWSDispatch.sendingQueue, ^(NSError *error) {
// Update the thread's friend request status if needed // Loki
// ========
if (messageType == TSFriendRequestMessageType) { if (messageType == TSFriendRequestMessageType) {
[message.thread setFriendRequestStatus:TSThreadFriendRequestStatusNone withTransaction:nil]; [message.thread setFriendRequestStatus:TSThreadFriendRequestStatusNone withTransaction:nil];
} }
// ========
// Handle the error // Handle the error
NSUInteger statusCode = 0; NSUInteger statusCode = 0;
NSData *_Nullable responseData = nil; NSData *_Nullable responseData = nil;

Loading…
Cancel
Save