diff --git a/Realtime/Conversation/LCIMConversation.cs b/Realtime/Conversation/LCIMConversation.cs index 2e40ddc..d6346a3 100644 --- a/Realtime/Conversation/LCIMConversation.cs +++ b/Realtime/Conversation/LCIMConversation.cs @@ -237,8 +237,11 @@ namespace LeanCloud.Realtime { /// /// public async Task Join() { - LCIMPartiallySuccessResult result = await AddMembers(new string[] { Client.Id }); - if (!result.IsSuccess) { + LCIMPartiallySuccessResult result = await Client.ConversationController.AddMembers(Id, + new string[] { Client.Id }); + if (result.IsSuccess) { + ids.UnionWith(result.SuccessfulClientIdList); + } else { LCIMOperationFailure error = result.FailureList[0]; throw new LCException(error.Code, error.Reason); } diff --git a/Realtime/Internal/Controller/LCIMConversationController.cs b/Realtime/Internal/Controller/LCIMConversationController.cs index cf33ca9..6b3e38f 100644 --- a/Realtime/Internal/Controller/LCIMConversationController.cs +++ b/Realtime/Internal/Controller/LCIMConversationController.cs @@ -563,6 +563,48 @@ namespace LeanCloud.Realtime.Internal.Controller { #region 消息处理 internal override async Task OnNotification(GenericCommand notification) { + if (notification.Cmd == CommandType.Conv) { + await OnConversation(notification); + } else if (notification.Cmd == CommandType.Unread) { + await OnUnread(notification); + } + } + + private async Task OnUnread(GenericCommand notification) { + UnreadCommand unread = notification.UnreadMessage; + + IEnumerable convIds = unread.Convs + .Select(conv => conv.Cid); + Dictionary conversationDict = (await Client.GetConversationList(convIds)) + .ToDictionary(item => item.Id); + ReadOnlyCollection conversations = unread.Convs.Select(conv => { + // 设置对话中的未读数据 + LCIMConversation conversation = conversationDict[conv.Cid]; + conversation.Unread = conv.Unread; + if (conv.HasData || conv.HasBinaryMsg) { + // 如果有消息,则反序列化 + LCIMMessage message = null; + if (conv.HasBinaryMsg) { + // 二进制消息 + byte[] bytes = conv.BinaryMsg.ToByteArray(); + message = LCIMBinaryMessage.Deserialize(bytes); + } else { + // 类型消息 + message = LCIMTypedMessage.Deserialize(conv.Data); + } + // 填充消息数据 + message.ConversationId = conv.Cid; + message.Id = conv.Mid; + message.FromClientId = conv.From; + message.SentTimestamp = conv.Timestamp; + conversation.LastMessage = message; + } + return conversation; + }).ToList().AsReadOnly(); + Client.OnUnreadMessagesCountUpdated?.Invoke(conversations); + } + + private async Task OnConversation(GenericCommand notification) { ConvCommand convMessage = notification.ConvMessage; switch (notification.Op) { case OpType.Joined: diff --git a/Realtime/Internal/Controller/LCIMMessageController.cs b/Realtime/Internal/Controller/LCIMMessageController.cs index 830328f..8378080 100644 --- a/Realtime/Internal/Controller/LCIMMessageController.cs +++ b/Realtime/Internal/Controller/LCIMMessageController.cs @@ -223,40 +223,20 @@ namespace LeanCloud.Realtime.Internal.Controller { #region 消息处理 internal override async Task OnNotification(GenericCommand notification) { - if (notification.Cmd == CommandType.Patch) { - await OnMessagePatched(notification); - } else if (notification.Cmd == CommandType.Direct) { + if (notification.Cmd == CommandType.Direct) { await OnMessaage(notification); + } else if (notification.Cmd == CommandType.Patch) { + await OnMessagePatched(notification); + } else if (notification.Cmd == CommandType.Rcp) { + await OnMessageReceipt(notification); } } - private async Task OnMessagePatched(GenericCommand notification) { - PatchCommand patchMessage = notification.PatchMessage; - foreach (PatchItem patch in patchMessage.Patches) { - // 获取对话 - LCIMConversation conversation = await Client.GetOrQueryConversation(patch.Cid); - LCIMMessage message; - if (patch.HasBinaryMsg) { - byte[] bytes = patch.BinaryMsg.ToByteArray(); - message = LCIMBinaryMessage.Deserialize(bytes); - } else { - message = LCIMTypedMessage.Deserialize(patch.Data); - } - message.ConversationId = patch.Cid; - message.Id = patch.Mid; - message.FromClientId = patch.From; - message.SentTimestamp = patch.Timestamp; - message.PatchedTimestamp = patch.PatchTimestamp; - if (message is LCIMRecalledMessage recalledMessage) { - // 消息撤回 - Client.OnMessageRecalled?.Invoke(conversation, recalledMessage); - } else { - // 消息修改 - Client.OnMessageUpdated?.Invoke(conversation, message); - } - } - } - + /// + /// 接收消息事件 + /// + /// + /// private async Task OnMessaage(GenericCommand notification) { DirectCommand direct = notification.DirectMessage; // 反序列化消息 @@ -289,6 +269,58 @@ namespace LeanCloud.Realtime.Internal.Controller { Client.OnMessage?.Invoke(conversation, message); } + /// + /// 消息被修改事件 + /// + /// + /// + private async Task OnMessagePatched(GenericCommand notification) { + PatchCommand patchMessage = notification.PatchMessage; + foreach (PatchItem patch in patchMessage.Patches) { + // 获取对话 + LCIMConversation conversation = await Client.GetOrQueryConversation(patch.Cid); + LCIMMessage message; + if (patch.HasBinaryMsg) { + byte[] bytes = patch.BinaryMsg.ToByteArray(); + message = LCIMBinaryMessage.Deserialize(bytes); + } else { + message = LCIMTypedMessage.Deserialize(patch.Data); + } + message.ConversationId = patch.Cid; + message.Id = patch.Mid; + message.FromClientId = patch.From; + message.SentTimestamp = patch.Timestamp; + message.PatchedTimestamp = patch.PatchTimestamp; + if (message is LCIMRecalledMessage recalledMessage) { + // 消息撤回 + Client.OnMessageRecalled?.Invoke(conversation, recalledMessage); + } else { + // 消息修改 + Client.OnMessageUpdated?.Invoke(conversation, message); + } + } + } + + /// + /// 消息回执事件 + /// + /// + /// + private async Task OnMessageReceipt(GenericCommand notification) { + RcpCommand rcp = notification.RcpMessage; + string convId = rcp.Cid; + string msgId = rcp.Id; + long timestamp = rcp.T; + bool isRead = rcp.Read; + string fromId = rcp.From; + LCIMConversation conversation = await Client.GetOrQueryConversation(convId); + if (isRead) { + Client.OnMessageRead?.Invoke(conversation, msgId); + } else { + Client.OnMessageDelivered?.Invoke(conversation, msgId); + } + } + #endregion } } diff --git a/Realtime/Internal/Controller/LCIMRcpController.cs b/Realtime/Internal/Controller/LCIMRcpController.cs deleted file mode 100644 index 7760117..0000000 --- a/Realtime/Internal/Controller/LCIMRcpController.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Threading.Tasks; -using LeanCloud.Realtime.Protocol; - -namespace LeanCloud.Realtime.Internal.Controller { - internal class LCIMRcpController : LCIMController { - internal LCIMRcpController(LCIMClient client) : base(client) { - - } - - #region 消息处理 - - internal override async Task OnNotification(GenericCommand notification) { - RcpCommand rcp = notification.RcpMessage; - string convId = rcp.Cid; - string msgId = rcp.Id; - long timestamp = rcp.T; - bool isRead = rcp.Read; - string fromId = rcp.From; - LCIMConversation conversation = await Client.GetOrQueryConversation(convId); - if (isRead) { - Client.OnMessageRead?.Invoke(conversation, msgId); - } else { - Client.OnMessageDelivered?.Invoke(conversation, msgId); - } - } - - #endregion - } -} diff --git a/Realtime/Internal/Controller/LCIMUnreadController.cs b/Realtime/Internal/Controller/LCIMUnreadController.cs deleted file mode 100644 index aab34dc..0000000 --- a/Realtime/Internal/Controller/LCIMUnreadController.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using LeanCloud.Realtime.Protocol; - -namespace LeanCloud.Realtime.Internal.Controller { - internal class LCIMUnreadController : LCIMController { - internal LCIMUnreadController(LCIMClient client) : base(client) { - - } - - #region 消息处理 - - internal override async Task OnNotification(GenericCommand notification) { - UnreadCommand unread = notification.UnreadMessage; - - IEnumerable convIds = unread.Convs - .Select(conv => conv.Cid); - Dictionary conversationDict = (await Client.GetConversationList(convIds)) - .ToDictionary(item => item.Id); - ReadOnlyCollection conversations = unread.Convs.Select(conv => { - // 设置对话中的未读数据 - LCIMConversation conversation = conversationDict[conv.Cid]; - conversation.Unread = conv.Unread; - if (conv.HasData || conv.HasBinaryMsg) { - // 如果有消息,则反序列化 - LCIMMessage message = null; - if (conv.HasBinaryMsg) { - // 二进制消息 - byte[] bytes = conv.BinaryMsg.ToByteArray(); - message = LCIMBinaryMessage.Deserialize(bytes); - } else { - // 类型消息 - message = LCIMTypedMessage.Deserialize(conv.Data); - } - // 填充消息数据 - message.ConversationId = conv.Cid; - message.Id = conv.Mid; - message.FromClientId = conv.From; - message.SentTimestamp = conv.Timestamp; - conversation.LastMessage = message; - } - return conversation; - }).ToList().AsReadOnly(); - Client.OnUnreadMessagesCountUpdated?.Invoke(conversations); - } - - #endregion - } -} diff --git a/Realtime/LCIMClient.cs b/Realtime/LCIMClient.cs index a5e7c24..8c2f3d1 100644 --- a/Realtime/LCIMClient.cs +++ b/Realtime/LCIMClient.cs @@ -231,10 +231,6 @@ namespace LeanCloud.Realtime { get; private set; } - internal LCIMUnreadController UnreadController { - get; private set; - } - internal LCIMGoAwayController GoAwayController { get; private set; } @@ -243,10 +239,6 @@ namespace LeanCloud.Realtime { get; private set; } - internal LCIMRcpController RcpController { - get; private set; - } - #region 接口 public LCIMClient(string clientId, @@ -289,9 +281,7 @@ namespace LeanCloud.Realtime { SessionController = new LCIMSessionController(this); ConversationController = new LCIMConversationController(this); MessageController = new LCIMMessageController(this); - UnreadController = new LCIMUnreadController(this); GoAwayController = new LCIMGoAwayController(this); - RcpController = new LCIMRcpController(this); Connection = new LCConnection(Id) { OnNotification = OnConnectionNotification, @@ -446,21 +436,17 @@ namespace LeanCloud.Realtime { _ = SessionController.OnNotification(notification); break; case CommandType.Conv: + case CommandType.Unread: _ = ConversationController.OnNotification(notification); break; case CommandType.Direct: case CommandType.Patch: + case CommandType.Rcp: _ = MessageController.OnNotification(notification); break; - case CommandType.Unread: - _ = UnreadController.OnNotification(notification); - break; case CommandType.Goaway: _ = GoAwayController.OnNotification(notification); break; - case CommandType.Rcp: - _ = RcpController.OnNotification(notification); - break; default: break; } diff --git a/Test/Realtime.Test/Message.cs b/Test/Realtime.Test/Message.cs index 47d2494..c721a41 100644 --- a/Test/Realtime.Test/Message.cs +++ b/Test/Realtime.Test/Message.cs @@ -1,12 +1,14 @@ using NUnit.Framework; -using System.Collections.ObjectModel; +using System; +using System.Threading; using System.Threading.Tasks; +using System.Collections.Generic; using LeanCloud; using LeanCloud.Common; using LeanCloud.Storage; using LeanCloud.Realtime; -using static NUnit.Framework.TestContext; +using static System.Console; namespace Realtime.Test { public class Message { @@ -34,25 +36,16 @@ namespace Realtime.Test { } [Test] - [Order(0)] public async Task Send() { - TaskCompletionSource tcs = new TaskCompletionSource(); - - int count = 0; + AutoResetEvent are = new AutoResetEvent(false); m2.OnMessage = (conv, msg) => { WriteLine(msg.Id); if (msg is LCIMImageMessage imageMsg) { WriteLine($"-------- url: {imageMsg.Url}"); - count++; } else if (msg is LCIMFileMessage fileMsg) { WriteLine($"-------- name: {fileMsg.Format}"); - count++; } else if (msg is LCIMTextMessage textMsg) { WriteLine($"-------- text: {textMsg.Text}"); - count++; - } - if (count >= 3) { - tcs.SetResult(null); } }; @@ -71,79 +64,6 @@ namespace Realtime.Test { LCIMFileMessage fileMessage = new LCIMFileMessage(file); await conversation.Send(fileMessage); Assert.NotNull(fileMessage.Id); - - await tcs.Task; - } - - [Test] - [Order(1)] - public async Task AckAndRead() { - TaskCompletionSource tcs = new TaskCompletionSource(); - m2.OnMessage = async (conv, msg) => { - await conv.Read(); - }; - m1.OnMessageDelivered = (conv, msgId) => { - WriteLine($"{msgId} is delivered."); - }; - m1.OnMessageRead = (conv, msgId) => { - WriteLine($"{msgId} is read."); - tcs.SetResult(null); - }; - LCIMTextMessage textMessage = new LCIMTextMessage("hello"); - LCIMMessageSendOptions options = new LCIMMessageSendOptions { - Receipt = true - }; - await conversation.Send(textMessage, options); - - await tcs.Task; - } - - [Test] - [Order(2)] - public async Task Recall() { - TaskCompletionSource tcs = new TaskCompletionSource(); - m2.OnMessageRecalled = (conv, msgId) => { - WriteLine($"{msgId} is recalled."); - tcs.SetResult(null); - }; - LCIMTextMessage textMessage = new LCIMTextMessage("I will be recalled."); - await conversation.Send(textMessage); - await Task.Delay(1000); - await conversation.RecallMessage(textMessage); - - await tcs.Task; - } - - [Test] - [Order(3)] - public async Task Update() { - TaskCompletionSource tcs = new TaskCompletionSource(); - m2.OnMessageUpdated = (conv, msg) => { - Assert.True(msg is LCIMTextMessage); - LCIMTextMessage textMessage = msg as LCIMTextMessage; - Assert.AreEqual(textMessage.Text, "world"); - WriteLine($"{msg.Id} is updated"); - tcs.SetResult(null); - }; - LCIMTextMessage oldMessage = new LCIMTextMessage("hello"); - await conversation.Send(oldMessage); - await Task.Delay(1000); - LCIMTextMessage newMessage = new LCIMTextMessage("world"); - await conversation.UpdateMessage(oldMessage, newMessage); - - await tcs.Task; - } - - [Test] - [Order(4)] - public async Task Query() { - ReadOnlyCollection messages = await conversation.QueryMessages(); - Assert.Greater(messages.Count, 0); - foreach (LCIMMessage message in messages) { - Assert.AreEqual(message.ConversationId, conversation.Id); - Assert.NotNull(message.Id); - WriteLine(message.Id); - } } } }