* LCIMClient.cs:

* LCConnection.cs:
* LCWebSocketClient.cs:

* Program.cs: chore
oneRain 2020-04-13 10:47:14 +08:00
parent aeb063f6f8
commit b89709b21d
4 changed files with 85 additions and 16 deletions

View File

@ -9,6 +9,9 @@ using LeanCloud.Common;
using LeanCloud.Storage; using LeanCloud.Storage;
namespace LeanCloud.Realtime.Internal.Connection { namespace LeanCloud.Realtime.Internal.Connection {
/// <summary>
/// 连接层,只与数据协议相关
/// </summary>
internal class LCConnection { internal class LCConnection {
private const int SEND_TIMEOUT = 10000; private const int SEND_TIMEOUT = 10000;

View File

@ -5,6 +5,9 @@ using LeanCloud.Common;
using LeanCloud.Realtime.Internal.Router; using LeanCloud.Realtime.Internal.Router;
namespace LeanCloud.Realtime.Internal.WebSocket { namespace LeanCloud.Realtime.Internal.WebSocket {
/// <summary>
/// WebSocket 客户端,只与通信协议相关
/// </summary>
internal class LCWebSocketClient { internal class LCWebSocketClient {
// .net standard 2.0 好像在拼合 Frame 时有 bug所以将这个值调整大一些 // .net standard 2.0 好像在拼合 Frame 时有 bug所以将这个值调整大一些
private const int RECV_BUFFER_SIZE = 1024 * 5; private const int RECV_BUFFER_SIZE = 1024 * 5;
@ -28,11 +31,11 @@ namespace LeanCloud.Realtime.Internal.WebSocket {
internal async Task Connect() { internal async Task Connect() {
LCRTMServer rtmServer = await router.GetServer(); LCRTMServer rtmServer = await router.GetServer();
try { try {
LCLogger.Debug($"Connect Primary Server"); LCLogger.Debug($"Primary Server");
await Connect(rtmServer.Primary); await Connect(rtmServer.Primary);
} catch (Exception e) { } catch (Exception e) {
LCLogger.Error(e.Message); LCLogger.Error(e.Message);
LCLogger.Debug($"Connect Secondary"); LCLogger.Debug($"Secondary Server");
await Connect(rtmServer.Secondary); await Connect(rtmServer.Secondary);
} }
@ -41,7 +44,7 @@ namespace LeanCloud.Realtime.Internal.WebSocket {
} }
private async Task Connect(string server) { private async Task Connect(string server) {
LCLogger.Debug($"Connect WebSocket: {server}"); LCLogger.Debug($"Connecting WebSocket: {server}");
Task timeoutTask = Task.Delay(5000); Task timeoutTask = Task.Delay(5000);
ws = new ClientWebSocket(); ws = new ClientWebSocket();
ws.Options.AddSubProtocol("lc.protobuf2.3"); ws.Options.AddSubProtocol("lc.protobuf2.3");
@ -54,6 +57,7 @@ namespace LeanCloud.Realtime.Internal.WebSocket {
} }
internal async Task Close() { internal async Task Close() {
LCLogger.Debug("Closing WebSocket");
OnMessage = null; OnMessage = null;
OnDisconnect = null; OnDisconnect = null;
OnReconnect = null; OnReconnect = null;
@ -68,7 +72,7 @@ namespace LeanCloud.Realtime.Internal.WebSocket {
} finally { } finally {
ws.Abort(); ws.Abort();
ws.Dispose(); ws.Dispose();
LCLogger.Debug("Closed WebSocket."); LCLogger.Debug("Closed WebSocket");
} }
} }
@ -82,7 +86,9 @@ namespace LeanCloud.Realtime.Internal.WebSocket {
throw e; throw e;
} }
} else { } else {
throw new Exception($"Error Websocket state: {ws.State}"); string message = $"Error Websocket state: {ws.State}";
LCLogger.Error(message);
throw new Exception(message);
} }
} }

View File

@ -9,6 +9,9 @@ using LeanCloud.Realtime.Internal.Controller;
using LeanCloud.Realtime.Internal.Connection; using LeanCloud.Realtime.Internal.Connection;
namespace LeanCloud.Realtime { namespace LeanCloud.Realtime {
/// <summary>
/// 通信客户端
/// </summary>
public class LCIMClient { public class LCIMClient {
internal Dictionary<string, LCIMConversation> ConversationDict; internal Dictionary<string, LCIMConversation> ConversationDict;
@ -185,6 +188,20 @@ namespace LeanCloud.Realtime {
get; set; get; set;
} }
/// <summary>
/// 消息已送达
/// </summary>
public Action<LCIMConversation, string> OnMessageDelivered {
get; set;
}
/// <summary>
/// 消息已读
/// </summary>
public Action<LCIMConversation, string> OnMessageRead {
get; set;
}
/// <summary> /// <summary>
/// 未读消息数目更新 /// 未读消息数目更新
/// </summary> /// </summary>
@ -233,6 +250,10 @@ 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,
@ -246,6 +267,7 @@ namespace LeanCloud.Realtime {
MessageController = new LCIMMessageController(this); MessageController = new LCIMMessageController(this);
UnreadController = new LCIMUnreadController(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,
@ -410,6 +432,9 @@ namespace LeanCloud.Realtime {
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

@ -14,14 +14,23 @@ namespace RealtimeConsole {
LCLogger.LogDelegate += (level, info) => { LCLogger.LogDelegate += (level, info) => {
switch (level) { switch (level) {
case LCLogLevel.Debug: case LCLogLevel.Debug: {
Console.WriteLine($"[DEBUG]\n{info}"); Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"{DateTime.Now} [DEBUG]\n{info}");
Console.ResetColor();
}
break; break;
case LCLogLevel.Warn: case LCLogLevel.Warn: {
Console.WriteLine($"[WARNING]\n{info}"); Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"{DateTime.Now} [WARNING]\n{info}");
Console.ResetColor();
}
break; break;
case LCLogLevel.Error: case LCLogLevel.Error: {
Console.WriteLine($"[ERROR]\n{info}"); Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"{DateTime.Now} [ERROR]\n{info}");
Console.ResetColor();
}
break; break;
default: default:
Console.WriteLine(info); Console.WriteLine(info);
@ -32,14 +41,22 @@ namespace RealtimeConsole {
SingleThreadSynchronizationContext.Run(async () => { SingleThreadSynchronizationContext.Run(async () => {
Console.WriteLine($"start at {Thread.CurrentThread.ManagedThreadId}"); Console.WriteLine($"start at {Thread.CurrentThread.ManagedThreadId}");
await Run("cc4"); //await Run("cc1");
//await ChatRoom(); //await ChatRoom();
//await TemporaryConversation(); //await TemporaryConversation();
//await CreateConversation(); //await CreateConversation();
//await QueryMyConversation(); //await QueryMyConversation();
//await AutoSendMessage();
//await KeepAlive();
await OpenAndClose();
Console.WriteLine($"done at {Thread.CurrentThread.ManagedThreadId}"); Console.WriteLine($"done at {Thread.CurrentThread.ManagedThreadId}");
}); });
//AutoSendMessage().Wait();
//Conversation().Wait(); //Conversation().Wait();
//_ = Signature(); //_ = Signature();
@ -65,6 +82,24 @@ namespace RealtimeConsole {
Console.ReadKey(true); Console.ReadKey(true);
} }
static async Task KeepAlive() {
LCIMClient client = new LCIMClient("cc1");
await client.Open();
}
static async Task AutoSendMessage() {
LCIMClient client = new LCIMClient("cc1");
await client.Open();
LCIMConversation conversation = await client.CreateConversation(new string[] { "cc2", "cc3", "cc5" });
int count = 0;
while (count < 10) {
LCIMTextMessage textMessage = new LCIMTextMessage($"hello, {count}");
await conversation.Send(textMessage);
await Task.Delay(5000);
count++;
}
}
static async Task DemoAsync() { static async Task DemoAsync() {
Dictionary<int, int> d = new Dictionary<int, int>(); Dictionary<int, int> d = new Dictionary<int, int>();
for (int i = 0; i < 10000; i++) { for (int i = 0; i < 10000; i++) {
@ -86,17 +121,16 @@ namespace RealtimeConsole {
Console.WriteLine($"unread: {conv.Id}"); Console.WriteLine($"unread: {conv.Id}");
} }
}; };
client.OnMessage = (conversation, message) => { client.OnMessage = async (conversation, message) => {
Console.WriteLine($"recv: {conversation.Id}, {message.Id} at {Thread.CurrentThread.ManagedThreadId}"); Console.WriteLine($"recv: {conversation.Id}, {message.Id} at {Thread.CurrentThread.ManagedThreadId}");
await conversation.Read();
}; };
} }
static async Task CreateConversation() { static async Task CreateConversation() {
LCIMClient cc1 = new LCIMClient("cc1"); LCIMClient cc1 = new LCIMClient("cc1");
await cc1.Open(); await cc1.Open();
//await cc1.CreateChatRoom("leancloud chat"); await cc1.CreateConversation(new string[] { "cc2", "cc3", "cc5" });
await cc1.CreateTemporaryConversation(new string[] { "cc2", "cc3" });
//await cc1.CreateConversation(new string[] { "cc4" });
} }
static async Task QueryMyConversation() { static async Task QueryMyConversation() {
@ -146,6 +180,7 @@ namespace RealtimeConsole {
static async Task OpenAndClose() { static async Task OpenAndClose() {
LCIMClient o1 = new LCIMClient("o1"); LCIMClient o1 = new LCIMClient("o1");
await o1.Open(); await o1.Open();
await Task.Delay(30000);
await o1.Close(); await o1.Close();
} }