コード例 #1
0
ファイル: ChatWorker.cs プロジェクト: xds-playgrounds/xds-sdk
        async Task DecryptDownloadedMessage(XMessage xMessage)
        {
            Message decryptedMessage = await TryDecryptMessageToFindSenderEnryptDecryptionKeyAndSaveIt(xMessage);

            if (decryptedMessage == null) // TODO: we'll be here also when Ratchet mismatch error is happening. Then, the message should not be just dropped. Do we have the sender's Id so that we can notify him?
            {
                return;                   // Ignore the message - it was truely garbled or a resend request was already queued. In both cases we are done with it here.
            }
            if (decryptedMessage.MessageType.IsReceipt())
            {
                Message messageToConfirm = await this.repo.GetMessage(decryptedMessage.SenderLocalMessageId, decryptedMessage.SenderId);

                if (messageToConfirm != null) // the message could have already been deleted
                {
                    messageToConfirm.SendMessageState = decryptedMessage.MessageType == MessageType.DeliveryReceipt ? SendMessageState.Delivered : SendMessageState.Read;
                    await this.repo.UpdateMessage(messageToConfirm);

                    SendMessageStateUpdated?.Invoke(this, messageToConfirm);
                }
                return;
            }

            if (decryptedMessage.MessageType.IsContent())
            {
                if (this.contactListManager.CurrentContact == null || this.contactListManager.CurrentContact.Id != decryptedMessage.SenderId)
                {
                    await SendReceipt(decryptedMessage, MessageType.DeliveryReceipt);

                    // This message will become an UNREAD message and not be displayed
                    await this.contactListManager.HandelUnreadAndChatPreviewForIncomingMessageFromChatWorker(decryptedMessage, countAsUnread : true);
                }
                else
                {
                    await SendReceipt(decryptedMessage, MessageType.ReadReceipt);

                    // this message will become an READ message and display immediately
                    await this.contactListManager.HandelUnreadAndChatPreviewForIncomingMessageFromChatWorker(decryptedMessage, countAsUnread : false);

                    IncomingMessageDecrypted?.Invoke(this, decryptedMessage);
                }
            }

            #region Incoming Contact Logic
            // Check if the sender is in our contacts
            // OLD: Identity contactInList = existingContacts.SingleOrDefault(c => c.ChatId == msg.SenderId);

            /*
             *          Identity contactInList = existingContacts.SingleOrDefault(c => c.ChatId == msg.SenderId);
             *          if (contactInList != null && contactInList.ContactState == ContactState.Valid)
             *                  continue; // Yes, proceed checking the nex message
             *
             *          if (contactInList != null && contactInList.ContactState == ContactState.Added)
             *          {
             *                  await VerifyContactInAddedState(contactInList);
             *
             *                  // Check if the contact is valid now
             *                  existingContacts = await repo.GetAllContacts();
             *                  contactInList = existingContacts.SingleOrDefault(c => c.ChatId == msg.SenderId);
             *                  if (contactInList.ContactState == ContactState.Valid)
             *                          continue; // Yes, proceed checking the nex message
             *
             *                  // If still not valid, drop the message
             *                  msg.MessageType = MessageType.None; // MessageType.None will be ignored by the code below
             *                  continue; // Proceed checking the nex message
             *          }
             *          var incomingContact = new Identity { Id = Guid.NewGuid().ToString(), UnverifiedId=msg.SenderId, ContactState = ContactState.Added, Name = "Incoming Contact" };
             *          await repo.AddContact(incomingContact);
             *          await VerifyContactInAddedState(incomingContact);
             *
             *          // Check if the incoming contact is valid now
             *          existingContacts = await repo.GetAllContacts();
             *          contactInList = existingContacts.SingleOrDefault(c => c.ChatId == msg.SenderId);
             *          if (contactInList.ContactState == ContactState.Valid)
             *                  continue; // Yes, proceed checking the next message
             *
             *          // If still not valid, drop the message
             *          msg.MessageType = MessageType.None; // MessageType.None will be ignored by the code below
             */
            #endregion
        }
コード例 #2
0
ファイル: ChatWorker.cs プロジェクト: xds-playgrounds/xds-sdk
        async Task CheckForResendRequestsAsync()
        {
            // 1. Get the hashes of messages where we did not get a delivery or read receipt
            var contacts = await this.repo.GetAllContacts();

            foreach (var c in contacts.Where(c => c.ContactState == ContactState.Valid).ToArray())
            {
                // First, look at the last message and try to detect cases where simply everything is ok
                var lastMessage = await this.repo.GetLastMessage(c.Id);

                if (lastMessage == null || // if there is no message, there is nothing to resend
                    lastMessage.Side == MessageSide.You || // if the last message was incoming, it means the other side has the keys, it's ok
                    lastMessage.SendMessageState == SendMessageState.Delivered || lastMessage.SendMessageState == SendMessageState.Read)   // also nothing to repair
                {
                    continue;
                }

                // Now let's look deeper. We may have sent a couple of messages, that are all still without receipts. That means our state is XDSNetwork.
                // It's possible they could't be read, and the other side has already posted resend requests.
                // Of course it's also possible the other side has just been offline though. Unfortunately, we don't know.
                var moreLastMessages = await this.repo.GetMessageRange(0, 10, c.Id);

                foreach (var message in moreLastMessages)
                {
                    if (message.Side == MessageSide.Me && message.SendMessageState == SendMessageState.XDSNetwork && message.SendMessageState != SendMessageState.Resent &&
                        DateTime.UtcNow - message.GetEncrytedDateUtc() > TimeSpan.FromSeconds(60) && // old enough to check
                        DateTime.UtcNow - message.GetEncrytedDateUtc() < TimeSpan.FromDays(7))    // young enough not to be expired
                    {
                        var resendRequestQuery = new XResendRequest {
                            Id = message.NetworkPayloadHash, RecipientId = c.ChatId
                        };
                        var response = await this.chatClient.CheckForResendRequest(resendRequestQuery); // check if resend request has been posted, or if the sent message is still there and has not yet been fetched.

                        if (!response.IsSuccess)
                        {
                            return; // give up the whole procedure for all contacts, something else is broken
                        }
                        if (response.Result == 0)
                        {
                            // There is nothing on the server. Not the original message and no resend request. Possible causes:
                            // - The recipient did download it but did not send a resend request, or a receipt yet.
                            // - The message or receipt or resend request was lost.
                            // => keep checking. It's possible a resend request or receipt arrives, it drops out the top 10 we are checking
                            // or max ago for checking after messages arrives, so that we stop checking eventually.
                            // => but do not resend the message.
                            // => but do check the other messages of this contact.
                            message.SendMessageState = SendMessageState.Untracable;
                            await this.repo.UpdateMessage(message);

                            SendMessageStateUpdated?.Invoke(this, message);
                            continue;
                        }

                        if (response.Result == 1)
                        {
                            // The original message is still on the server.
                            // - The recipient hasn't downloaded his messages.
                            // => stop checking this contact
                            break;
                        }

                        if (response.Result == 2)
                        {
                            // yes, there is a resend request on the server.
                            // => resend the message
                            await this.chatEncryptionService.DecryptCipherTextInVisibleBubble(message);

                            await this.chatEncryptionService.EncryptMessage(message, true);

                            var resendResponse = await this.chatClient.UploadMessage(message);

                            if (resendResponse.IsSuccess)
                            {
                                message.SendMessageState = SendMessageState.Resent;
                                await this.repo.UpdateMessage(message);

                                SendMessageStateUpdated?.Invoke(this, message);
                            }
                        }
                    }
                }
            }
        }