* LCIMClient.cs:

* LCIMMessage.cs:
* LCIMTypedMessage.cs:
* LCIMRecalledMessage.cs:
* LCIMConversation.cs:
* LCIMRcpController.cs:
* LCIMUnreadController.cs:
* LCIMMessageController.cs:
* LCIMSessionController.cs:

* LCIMConversationController.cs: chore: 完善功能模块
oneRain 2020-04-26 16:14:45 +08:00
parent f852fe2264
commit 48b0de3301
7 changed files with 116 additions and 213 deletions

View File

@ -237,8 +237,11 @@ namespace LeanCloud.Realtime {
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task Join() { public async Task Join() {
LCIMPartiallySuccessResult result = await AddMembers(new string[] { Client.Id }); LCIMPartiallySuccessResult result = await Client.ConversationController.AddMembers(Id,
if (!result.IsSuccess) { new string[] { Client.Id });
if (result.IsSuccess) {
ids.UnionWith(result.SuccessfulClientIdList);
} else {
LCIMOperationFailure error = result.FailureList[0]; LCIMOperationFailure error = result.FailureList[0];
throw new LCException(error.Code, error.Reason); throw new LCException(error.Code, error.Reason);
} }

View File

@ -563,6 +563,48 @@ namespace LeanCloud.Realtime.Internal.Controller {
#region 消息处理 #region 消息处理
internal override async Task OnNotification(GenericCommand notification) { 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<string> convIds = unread.Convs
.Select(conv => conv.Cid);
Dictionary<string, LCIMConversation> conversationDict = (await Client.GetConversationList(convIds))
.ToDictionary(item => item.Id);
ReadOnlyCollection<LCIMConversation> 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; ConvCommand convMessage = notification.ConvMessage;
switch (notification.Op) { switch (notification.Op) {
case OpType.Joined: case OpType.Joined:

View File

@ -223,40 +223,20 @@ namespace LeanCloud.Realtime.Internal.Controller {
#region 消息处理 #region 消息处理
internal override async Task OnNotification(GenericCommand notification) { internal override async Task OnNotification(GenericCommand notification) {
if (notification.Cmd == CommandType.Patch) { if (notification.Cmd == CommandType.Direct) {
await OnMessagePatched(notification);
} else if (notification.Cmd == CommandType.Direct) {
await OnMessaage(notification); 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) { /// <summary>
PatchCommand patchMessage = notification.PatchMessage; /// 接收消息事件
foreach (PatchItem patch in patchMessage.Patches) { /// </summary>
// 获取对话 /// <param name="notification"></param>
LCIMConversation conversation = await Client.GetOrQueryConversation(patch.Cid); /// <returns></returns>
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) { private async Task OnMessaage(GenericCommand notification) {
DirectCommand direct = notification.DirectMessage; DirectCommand direct = notification.DirectMessage;
// 反序列化消息 // 反序列化消息
@ -289,6 +269,58 @@ namespace LeanCloud.Realtime.Internal.Controller {
Client.OnMessage?.Invoke(conversation, message); Client.OnMessage?.Invoke(conversation, message);
} }
/// <summary>
/// 消息被修改事件
/// </summary>
/// <param name="notification"></param>
/// <returns></returns>
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);
}
}
}
/// <summary>
/// 消息回执事件
/// </summary>
/// <param name="notification"></param>
/// <returns></returns>
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 #endregion
} }
} }

View File

@ -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
}
}

View File

@ -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<string> convIds = unread.Convs
.Select(conv => conv.Cid);
Dictionary<string, LCIMConversation> conversationDict = (await Client.GetConversationList(convIds))
.ToDictionary(item => item.Id);
ReadOnlyCollection<LCIMConversation> 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
}
}

View File

@ -231,10 +231,6 @@ namespace LeanCloud.Realtime {
get; private set; get; private set;
} }
internal LCIMUnreadController UnreadController {
get; private set;
}
internal LCIMGoAwayController GoAwayController { internal LCIMGoAwayController GoAwayController {
get; private set; get; private set;
} }
@ -243,10 +239,6 @@ namespace LeanCloud.Realtime {
get; private set; get; private set;
} }
internal LCIMRcpController RcpController {
get; private set;
}
#region 接口 #region 接口
public LCIMClient(string clientId, public LCIMClient(string clientId,
@ -289,9 +281,7 @@ namespace LeanCloud.Realtime {
SessionController = new LCIMSessionController(this); SessionController = new LCIMSessionController(this);
ConversationController = new LCIMConversationController(this); ConversationController = new LCIMConversationController(this);
MessageController = new LCIMMessageController(this); MessageController = new LCIMMessageController(this);
UnreadController = new LCIMUnreadController(this);
GoAwayController = new LCIMGoAwayController(this); GoAwayController = new LCIMGoAwayController(this);
RcpController = new LCIMRcpController(this);
Connection = new LCConnection(Id) { Connection = new LCConnection(Id) {
OnNotification = OnConnectionNotification, OnNotification = OnConnectionNotification,
@ -446,21 +436,17 @@ namespace LeanCloud.Realtime {
_ = SessionController.OnNotification(notification); _ = SessionController.OnNotification(notification);
break; break;
case CommandType.Conv: case CommandType.Conv:
case CommandType.Unread:
_ = ConversationController.OnNotification(notification); _ = ConversationController.OnNotification(notification);
break; break;
case CommandType.Direct: case CommandType.Direct:
case CommandType.Patch: case CommandType.Patch:
case CommandType.Rcp:
_ = MessageController.OnNotification(notification); _ = MessageController.OnNotification(notification);
break; break;
case CommandType.Unread:
_ = UnreadController.OnNotification(notification);
break;
case CommandType.Goaway: case CommandType.Goaway:
_ = GoAwayController.OnNotification(notification); _ = GoAwayController.OnNotification(notification);
break; break;
case CommandType.Rcp:
_ = RcpController.OnNotification(notification);
break;
default: default:
break; break;
} }

View File

@ -1,12 +1,14 @@
using NUnit.Framework; using NUnit.Framework;
using System.Collections.ObjectModel; using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Generic;
using LeanCloud; using LeanCloud;
using LeanCloud.Common; using LeanCloud.Common;
using LeanCloud.Storage; using LeanCloud.Storage;
using LeanCloud.Realtime; using LeanCloud.Realtime;
using static NUnit.Framework.TestContext; using static System.Console;
namespace Realtime.Test { namespace Realtime.Test {
public class Message { public class Message {
@ -34,25 +36,16 @@ namespace Realtime.Test {
} }
[Test] [Test]
[Order(0)]
public async Task Send() { public async Task Send() {
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(); AutoResetEvent are = new AutoResetEvent(false);
int count = 0;
m2.OnMessage = (conv, msg) => { m2.OnMessage = (conv, msg) => {
WriteLine(msg.Id); WriteLine(msg.Id);
if (msg is LCIMImageMessage imageMsg) { if (msg is LCIMImageMessage imageMsg) {
WriteLine($"-------- url: {imageMsg.Url}"); WriteLine($"-------- url: {imageMsg.Url}");
count++;
} else if (msg is LCIMFileMessage fileMsg) { } else if (msg is LCIMFileMessage fileMsg) {
WriteLine($"-------- name: {fileMsg.Format}"); WriteLine($"-------- name: {fileMsg.Format}");
count++;
} else if (msg is LCIMTextMessage textMsg) { } else if (msg is LCIMTextMessage textMsg) {
WriteLine($"-------- text: {textMsg.Text}"); WriteLine($"-------- text: {textMsg.Text}");
count++;
}
if (count >= 3) {
tcs.SetResult(null);
} }
}; };
@ -71,79 +64,6 @@ namespace Realtime.Test {
LCIMFileMessage fileMessage = new LCIMFileMessage(file); LCIMFileMessage fileMessage = new LCIMFileMessage(file);
await conversation.Send(fileMessage); await conversation.Send(fileMessage);
Assert.NotNull(fileMessage.Id); Assert.NotNull(fileMessage.Id);
await tcs.Task;
}
[Test]
[Order(1)]
public async Task AckAndRead() {
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
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<object> tcs = new TaskCompletionSource<object>();
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<object> tcs = new TaskCompletionSource<object>();
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<LCIMMessage> 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);
}
} }
} }
} }