* LCIMClient.cs:
* LCIMMessage.cs: * LCIMTypedMessage.cs: * LCIMRecalledMessage.cs: * LCIMConversation.cs: * LCIMRcpController.cs: * LCIMUnreadController.cs: * LCIMMessageController.cs: * LCIMSessionController.cs: * LCIMConversationController.cs: chore: 完善功能模块
parent
f852fe2264
commit
48b0de3301
|
@ -237,8 +237,11 @@ namespace LeanCloud.Realtime {
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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<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;
|
||||
switch (notification.Op) {
|
||||
case OpType.Joined:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 接收消息事件
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <returns></returns>
|
||||
private async Task OnMessaage(GenericCommand notification) {
|
||||
DirectCommand direct = notification.DirectMessage;
|
||||
// 反序列化消息
|
||||
|
@ -289,6 +269,58 @@ namespace LeanCloud.Realtime.Internal.Controller {
|
|||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<object> tcs = new TaskCompletionSource<object>();
|
||||
|
||||
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<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue