From 00a4fd3678a71d44fa6e4e7cb76168ecd491d45b Mon Sep 17 00:00:00 2001 From: yallie Date: Thu, 12 Dec 2024 19:13:58 +0300 Subject: [PATCH] Updated Quic channel for the new async channel API. --- .../CoreRemoting.Channels.Quic.csproj | 36 ++++----- .../QuicClientChannel.cs | 81 +++++++------------ .../QuicServerChannel.cs | 8 +- .../QuicServerConnection.cs | 15 ++-- CoreRemoting.Tests/CoreRemoting.Tests.csproj | 9 ++- CoreRemoting.Tests/RpcTests_Quic.cs | 17 ++++ CoreRemoting.sln | 6 ++ 7 files changed, 85 insertions(+), 87 deletions(-) create mode 100644 CoreRemoting.Tests/RpcTests_Quic.cs diff --git a/CoreRemoting.Channels.Quic/CoreRemoting.Channels.Quic.csproj b/CoreRemoting.Channels.Quic/CoreRemoting.Channels.Quic.csproj index 78540f2..d92193b 100644 --- a/CoreRemoting.Channels.Quic/CoreRemoting.Channels.Quic.csproj +++ b/CoreRemoting.Channels.Quic/CoreRemoting.Channels.Quic.csproj @@ -2,28 +2,24 @@ net9.0.0 - CoreRemoting.Channels.Quic - CoreRemoting.Channels.Quic - 1.2.1 - Alexey Yakovlev - Quic channels for CoreRemoting - 2024 Alexey Yakovlev - https://github.com/theRainbird/CoreRemoting - - true - CoreRemoting.Channels.Quic - https://github.com/theRainbird/CoreRemoting.git - git - 1.2.1 - 10 + CoreRemoting.Channels.Quic + CoreRemoting.Channels.Quic + 1.2.1 + Alexey Yakovlev + Quic channels for CoreRemoting + 2024 Alexey Yakovlev + https://github.com/theRainbird/CoreRemoting + + true + CoreRemoting.Channels.Quic + https://github.com/theRainbird/CoreRemoting.git + git + 1.2.1 + 12 - - 1701;1702;CA1416 - - - - 1701;1702;1416 + + $(NoWarn),1701;1702;CA1416;NU1701,NU1903 diff --git a/CoreRemoting.Channels.Quic/QuicClientChannel.cs b/CoreRemoting.Channels.Quic/QuicClientChannel.cs index 6dc5520..ebaaeaf 100644 --- a/CoreRemoting.Channels.Quic/QuicClientChannel.cs +++ b/CoreRemoting.Channels.Quic/QuicClientChannel.cs @@ -6,6 +6,7 @@ using System.Net.Security; using System.Text; using System.Threading.Tasks; +using CoreRemoting.Toolbox; namespace CoreRemoting.Channels.Quic; @@ -95,40 +96,31 @@ public void Init(IRemotingClient client) } /// - public void Connect() + public async Task ConnectAsync() { - ConnectTask = ConnectTask ?? Task.Factory.StartNew(async () => + // connect and open duplex stream + Connection = await QuicConnection.ConnectAsync(Options); + ClientStream = await Connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional); + ClientReader = new BinaryReader(ClientStream, Encoding.UTF8, leaveOpen: true); + ClientWriter = new BinaryWriter(ClientStream, Encoding.UTF8, leaveOpen: true); + + // prepare handshake message + var handshakeMessage = Array.Empty(); + if (Client.MessageEncryption) { - // connect and open duplex stream - Connection = await QuicConnection.ConnectAsync(Options); - ClientStream = await Connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional); - ClientReader = new BinaryReader(ClientStream, Encoding.UTF8, leaveOpen: true); - ClientWriter = new BinaryWriter(ClientStream, Encoding.UTF8, leaveOpen: true); - - // prepare handshake message - var handshakeMessage = Array.Empty(); - if (Client.MessageEncryption) - { - handshakeMessage = Client.PublicKey; - } - - // send handshake message - SendMessage(handshakeMessage); - IsConnected = true; - Connected?.Invoke(); + handshakeMessage = Client.PublicKey; + } - // start listening for incoming messages - _ = Task.Factory.StartNew(() => StartListening()); - }); + // send handshake message + await SendMessageAsync(handshakeMessage); + IsConnected = true; + Connected?.Invoke(); - ConnectTask.ConfigureAwait(false) - .GetAwaiter() - .GetResult(); + // start listening for incoming messages + _ = Task.Run(() => ReadIncomingMessages()); } - private Task ConnectTask { get; set; } - - private void StartListening() + private void ReadIncomingMessages() { try { @@ -136,10 +128,7 @@ private void StartListening() { var messageSize = ClientReader.Read7BitEncodedInt(); var message = ClientReader.ReadBytes(Math.Min(messageSize, MaxMessageSize)); - if (message.Length > 0) - { - ReceiveMessage(message); - } + ReceiveMessage(message); } } catch (Exception ex) @@ -152,12 +141,12 @@ private void StartListening() } finally { - Disconnect(); + DisconnectAsync().JustWait(); } } /// - public bool SendMessage(byte[] rawMessage) + public async Task SendMessageAsync(byte[] rawMessage) { try { @@ -167,7 +156,7 @@ public bool SendMessage(byte[] rawMessage) // message length + message body ClientWriter.Write7BitEncodedInt(rawMessage.Length); - ClientWriter.Write(rawMessage, 0, rawMessage.Length); + await ClientStream.WriteAsync(rawMessage, 0, rawMessage.Length); return true; } catch (Exception ex) @@ -180,17 +169,12 @@ public bool SendMessage(byte[] rawMessage) } } - private Task DisconnectTask { get; set; } - /// - public void Disconnect() + public async Task DisconnectAsync() { - DisconnectTask = DisconnectTask ?? Task.Factory.StartNew(async () => - { - await Connection.CloseAsync(0x0C); - IsConnected = false; - Disconnected?.Invoke(); - }); + await Connection.CloseAsync(0x0C); + IsConnected = false; + Disconnected?.Invoke(); } /// @@ -200,13 +184,8 @@ public void Dispose() return; if (IsConnected) - Disconnect(); - - var task = DisconnectTask; - if (task != null) - task.ConfigureAwait(false) - .GetAwaiter() - .GetResult(); + DisconnectAsync() + .JustWait(); Connection.DisposeAsync() .ConfigureAwait(false) diff --git a/CoreRemoting.Channels.Quic/QuicServerChannel.cs b/CoreRemoting.Channels.Quic/QuicServerChannel.cs index f7c0bc3..4b69f73 100644 --- a/CoreRemoting.Channels.Quic/QuicServerChannel.cs +++ b/CoreRemoting.Channels.Quic/QuicServerChannel.cs @@ -5,6 +5,7 @@ using System.Net.Quic; using System.Net.Security; using System.Threading.Tasks; +using CoreRemoting.Toolbox; namespace CoreRemoting.Channels.Quic; @@ -61,7 +62,7 @@ public void Init(IRemotingServer server) /// public void StartListening() { - _ = Task.Factory.StartNew(async () => + _ = Task.Run(async () => { // start the listener Listener = await QuicListener.ListenAsync(new QuicListenerOptions() @@ -100,10 +101,7 @@ public void StopListening() if (Listener != null && IsListening) { IsListening = false; - Listener.DisposeAsync() - .ConfigureAwait(false) - .GetAwaiter() - .GetResult(); + Listener.DisposeAsync().JustWait(); } } diff --git a/CoreRemoting.Channels.Quic/QuicServerConnection.cs b/CoreRemoting.Channels.Quic/QuicServerConnection.cs index c10a18e..cfef26f 100644 --- a/CoreRemoting.Channels.Quic/QuicServerConnection.cs +++ b/CoreRemoting.Channels.Quic/QuicServerConnection.cs @@ -3,6 +3,7 @@ using System.Net.Quic; using System.Text; using System.Threading.Tasks; +using CoreRemoting.Toolbox; namespace CoreRemoting.Channels.Quic; @@ -52,7 +53,7 @@ public QuicServerConnection(QuicConnection connection, QuicStream stream, IRemot public event Action Disconnected; /// - public bool SendMessage(byte[] rawMessage) + public async Task SendMessageAsync(byte[] rawMessage) { try { @@ -62,7 +63,7 @@ public bool SendMessage(byte[] rawMessage) // message length + message body ClientWriter.Write7BitEncodedInt(rawMessage.Length); - ClientWriter.Write(rawMessage, 0, rawMessage.Length); + await ClientStream.WriteAsync(rawMessage, 0, rawMessage.Length); return true; } catch (Exception ex) @@ -81,7 +82,7 @@ public bool SendMessage(byte[] rawMessage) public Guid StartListening() { var sessionId = CreateRemotingSession(); - _ = Task.Factory.StartNew(() => ReadIncomingMessages()); + _ = Task.Run(() => ReadIncomingMessages()); return sessionId; } @@ -117,11 +118,7 @@ private void ReadIncomingMessages() while (true) { var message = ReadIncomingMessage(); - if (message != null && message.Length > 0) - { - // flush received QUIC message - ReceiveMessage(message); - } + ReceiveMessage(message ?? []); } } catch (Exception ex) @@ -134,7 +131,7 @@ private void ReadIncomingMessages() } finally { - Connection?.DisposeAsync().ConfigureAwait(false).GetAwaiter().GetResult(); + Connection?.DisposeAsync().JustWait(); Connection = null; } } diff --git a/CoreRemoting.Tests/CoreRemoting.Tests.csproj b/CoreRemoting.Tests/CoreRemoting.Tests.csproj index c010a26..5e1c6fa 100644 --- a/CoreRemoting.Tests/CoreRemoting.Tests.csproj +++ b/CoreRemoting.Tests/CoreRemoting.Tests.csproj @@ -1,16 +1,17 @@  - net8.0 + net9.0 true false $(NoWarn),NU1701,NU1903 - + + @@ -33,6 +34,10 @@ + + + + diff --git a/CoreRemoting.Tests/RpcTests_Quic.cs b/CoreRemoting.Tests/RpcTests_Quic.cs new file mode 100644 index 0000000..e176e0e --- /dev/null +++ b/CoreRemoting.Tests/RpcTests_Quic.cs @@ -0,0 +1,17 @@ +using CoreRemoting.Channels; +using CoreRemoting.Channels.Quic; +using Xunit.Abstractions; + +namespace CoreRemoting.Tests +{ + public class RpcTests_Quic : RpcTests + { + protected override IServerChannel ServerChannel => new QuicServerChannel(); + + protected override IClientChannel ClientChannel => new QuicClientChannel(); + + public RpcTests_Quic(ServerFixture fixture, ITestOutputHelper helper) : base(fixture, helper) + { + } + } +} \ No newline at end of file diff --git a/CoreRemoting.sln b/CoreRemoting.sln index 6ad4702..481fd00 100644 --- a/CoreRemoting.sln +++ b/CoreRemoting.sln @@ -32,6 +32,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreRemoting.Tests.External EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreRemoting.Channels.WebsocketSharp", "CoreRemoting.Channels.WebsocketSharp\CoreRemoting.Channels.WebsocketSharp.csproj", "{A2440A47-F1F2-4556-958B-5CA19BF17A59}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreRemoting.Channels.Quic", "CoreRemoting.Channels.Quic\CoreRemoting.Channels.Quic.csproj", "{6CC666E2-A400-4409-A9CA-3583BE832A2C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -78,6 +80,10 @@ Global {A2440A47-F1F2-4556-958B-5CA19BF17A59}.Debug|Any CPU.Build.0 = Debug|Any CPU {A2440A47-F1F2-4556-958B-5CA19BF17A59}.Release|Any CPU.ActiveCfg = Release|Any CPU {A2440A47-F1F2-4556-958B-5CA19BF17A59}.Release|Any CPU.Build.0 = Release|Any CPU + {6CC666E2-A400-4409-A9CA-3583BE832A2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6CC666E2-A400-4409-A9CA-3583BE832A2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6CC666E2-A400-4409-A9CA-3583BE832A2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6CC666E2-A400-4409-A9CA-3583BE832A2C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE