diff --git a/src/CI/azp-dotnet-dist.yaml b/src/CI/azp-dotnet-dist.yaml index bafcc806..02e66263 100644 --- a/src/CI/azp-dotnet-dist.yaml +++ b/src/CI/azp-dotnet-dist.yaml @@ -16,7 +16,7 @@ steps: - task: DotNetCoreCLI@2 displayName: 'dotnet push to UiPath-Internal' - condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) + condition: succeeded() inputs: command: push packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg' @@ -24,7 +24,7 @@ steps: - task: PublishSymbols@2 displayName: 'Publish Symbols to UiPath Azure Artifacts Symbol Server' - condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) + condition: succeeded() inputs: symbolsFolder: $(Build.SourcesDirectory) searchPattern: '**/UiPath.CoreIpc/bin/**/UiPath.CoreIpc.pdb' diff --git a/src/CI/azp-dotnet.yaml b/src/CI/azp-dotnet.yaml index 0af4fc84..515a8ea1 100644 --- a/src/CI/azp-dotnet.yaml +++ b/src/CI/azp-dotnet.yaml @@ -1,4 +1,10 @@ steps: + - task: DotNetCoreCLI@2 + displayName: '$(Label_DotNet) Restore, build and pack' + inputs: + projects: '$(DotNet_SessionSolution)' + arguments: '--configuration $(DotNet_BuildConfiguration) -p:Version="$(FullVersion)" -p:DefineConstantsEx="CI"' + - task: DotNetCoreCLI@2 displayName: '$(Label_DotNet) Run unit tests' inputs: diff --git a/src/CI/azp-initialization.yaml b/src/CI/azp-initialization.yaml index 3cc0d0a3..2fd099a2 100644 --- a/src/CI/azp-initialization.yaml +++ b/src/CI/azp-initialization.yaml @@ -1,4 +1,20 @@ steps: + - powershell: | + Write-Host "##vso[task.setvariable variable=DotnetRuntimeVersion;]8.0.0" + Write-Host "##vso[task.setvariable variable=DOTNET_NOLOGO;]true" + displayName: 'Use .NET Runtime 8.0.0' + + - task: UseDotNet@2 + displayName: 'Use .NET SDK 6.0.317' + inputs: + packageType: 'sdk' + version: '6.0.317' + + - task: UseDotNet@2 + displayName: 'Use .NET SDK 8.x' + inputs: + packageType: 'sdk' + version: 8.x # Read $(Version) from the UiPath.CoreIpc.csproj file - powershell: | diff --git a/src/CI/azp-nodejs.yaml b/src/CI/azp-nodejs.yaml index 52f7d934..ee14c6bf 100644 --- a/src/CI/azp-nodejs.yaml +++ b/src/CI/azp-nodejs.yaml @@ -48,7 +48,7 @@ inputs: workingDirectory: $(NodeJS_ProjectPath) script: 'npm test' - + - task: PublishTestResults@2 displayName: 'Publish Web Test Results' condition: succeededOrFailed() diff --git a/src/CI/azp-start.yaml b/src/CI/azp-start.yaml index d659af93..d51e5497 100644 --- a/src/CI/azp-start.yaml +++ b/src/CI/azp-start.yaml @@ -10,7 +10,7 @@ variables: DotNet_MainProjectName: 'UiPath.CoreIpc' DotNet_MainProjectPath: './src/UiPath.CoreIpc/UiPath.CoreIpc.csproj' DotNet_ArtifactName: 'NuGet package' - + NodeJS_DotNet_BuildConfiguration: 'Debug' NodeJS_ProjectPath: './src/Clients/js' NodeJS_ArchivePath: './src/Clients/js/dist/pack/nodejs.zip' @@ -23,32 +23,32 @@ stages: - stage: Build displayName: '🏭 Build' jobs: - # The following 3 jobs will run in parallel: - - job: - displayName: '.NET on Windows' - pool: + # The following 3 jobs will run in parallel: + - job: + displayName: '.NET on Windows' + pool: vmImage: 'windows-2022' - steps: - - template: azp-initialization.yaml - - template: azp-dotnet.yaml - - template: azp-dotnet-dist.yaml - - - job: - displayName: 'node.js on Windows' - pool: + steps: + - template: azp-initialization.yaml + - template: azp-dotnet.yaml + - template: azp-dotnet-dist.yaml + + - job: + displayName: 'node.js on Windows' + pool: vmImage: 'windows-2022' - steps: - - template: azp-initialization.yaml - - template: azp-nodejs.yaml - - template: azp-nodejs-dist.yaml - - - job: - displayName: 'node.js on Ubuntu' - pool: - vmImage: 'ubuntu-20.04' - steps: - - template: azp-initialization.yaml - - template: azp-nodejs.yaml + steps: + - template: azp-initialization.yaml + - template: azp-nodejs.yaml + - template: azp-nodejs-dist.yaml + + - job: + displayName: 'node.js on Ubuntu' + pool: + vmImage: 'ubuntu-20.04' + steps: + - template: azp-initialization.yaml + - template: azp-nodejs.yaml - stage: Publish displayName: 🚚 Publish diff --git a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Contracts.cs b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Contracts.cs index 0a725bab..d86c0d8e 100644 --- a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Contracts.cs +++ b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Contracts.cs @@ -2,7 +2,7 @@ using System.Threading; using System.Threading.Tasks; -namespace UiPath.CoreIpc.NodeInterop; +namespace UiPath.Ipc.NodeInterop; internal static class Contracts { diff --git a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Program.cs b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Program.cs index 17f23329..02792bdd 100644 --- a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Program.cs +++ b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Program.cs @@ -7,10 +7,10 @@ using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; -using UiPath.CoreIpc.NamedPipe; -using UiPath.CoreIpc.WebSockets; +using UiPath.Ipc.NamedPipe; +using UiPath.Ipc.WebSockets; -namespace UiPath.CoreIpc.NodeInterop; +namespace UiPath.Ipc.NodeInterop; using static Contracts; using static ServiceImpls; diff --git a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/ServiceImpls.cs b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/ServiceImpls.cs index 0a436080..3b9706f1 100644 --- a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/ServiceImpls.cs +++ b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/ServiceImpls.cs @@ -3,7 +3,7 @@ using System.Threading; using System.Threading.Tasks; -namespace UiPath.CoreIpc.NodeInterop; +namespace UiPath.Ipc.NodeInterop; using static Contracts; diff --git a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Signalling.cs b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Signalling.cs index aba44d91..76d667f4 100644 --- a/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Signalling.cs +++ b/src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Signalling.cs @@ -2,7 +2,7 @@ using Newtonsoft.Json.Converters; using System; -namespace UiPath.CoreIpc.NodeInterop; +namespace UiPath.Ipc.NodeInterop; internal static class Signalling { diff --git a/src/CoreIpc.sln b/src/CoreIpc.sln index b69f1d5f..3ae701b3 100644 --- a/src/CoreIpc.sln +++ b/src/CoreIpc.sln @@ -13,6 +13,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiPath.CoreIpc.Tests", "UiP EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{676A208A-2F08-4749-A833-F8D2BCB1B147}" ProjectSection(SolutionItems) = preProject + Directory.Build.targets = Directory.Build.targets NuGet.Config = NuGet.Config EndProjectSection EndProject diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets new file mode 100644 index 00000000..4979abb6 --- /dev/null +++ b/src/Directory.Build.targets @@ -0,0 +1,5 @@ + + + + + diff --git a/src/IpcSample.ConsoleClient/Client.cs b/src/IpcSample.ConsoleClient/Client.cs index 36515be2..177ab7bf 100644 --- a/src/IpcSample.ConsoleClient/Client.cs +++ b/src/IpcSample.ConsoleClient/Client.cs @@ -1,9 +1,9 @@ using System.Text; using System.Diagnostics; -using UiPath.CoreIpc.NamedPipe; +using UiPath.Ipc.NamedPipe; using Microsoft.Extensions.DependencyInjection; -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; class Client { @@ -32,7 +32,7 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken) var serviceProvider = ConfigureServices(); var callback = new ComputingCallback { Id = "custom made" }; var computingClientBuilder = new NamedPipeClientBuilder("test", serviceProvider) - .SerializeParametersAsObjects().CallbackInstance(callback).AllowImpersonation().RequestTimeout(TimeSpan.FromSeconds(2)); + .CallbackInstance(callback).AllowImpersonation().RequestTimeout(TimeSpan.FromSeconds(2)); var stopwatch = Stopwatch.StartNew(); int count = 0; try @@ -40,7 +40,6 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken) var computingClient = computingClientBuilder.ValidateAndBuild(); var systemClient = new NamedPipeClientBuilder("test") - .SerializeParametersAsObjects() .RequestTimeout(TimeSpan.FromSeconds(2)) .Logger(serviceProvider) .AllowImpersonation() @@ -67,7 +66,7 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken) Console.WriteLine($"[TEST 3] sum of 3 complexe number is: {result3.A}+{result3.B}i", cancellationToken); // test 4: call IPC service method without parameter or return - await systemClient.DoNothing(cancellationToken); + await systemClient.FireAndForget(cancellationToken); Console.WriteLine($"[TEST 4] invoked DoNothing()"); //((IDisposable)systemClient).Dispose(); diff --git a/src/IpcSample.ConsoleClient/IpcSample.ConsoleClient.csproj b/src/IpcSample.ConsoleClient/IpcSample.ConsoleClient.csproj index a313c304..709ab56e 100644 --- a/src/IpcSample.ConsoleClient/IpcSample.ConsoleClient.csproj +++ b/src/IpcSample.ConsoleClient/IpcSample.ConsoleClient.csproj @@ -14,9 +14,9 @@ - - - - + + + + diff --git a/src/IpcSample.ConsoleClient/Polyfills.cs b/src/IpcSample.ConsoleClient/Polyfills.cs new file mode 100644 index 00000000..3f9caea2 --- /dev/null +++ b/src/IpcSample.ConsoleClient/Polyfills.cs @@ -0,0 +1,30 @@ +#if NETFRAMEWORK + +namespace System.Diagnostics.CodeAnalysis; + +using static AttributeTargets; + +[ExcludeFromCodeCoverage] +[DebuggerNonUserCode] +[AttributeUsage(Parameter | Property | ReturnValue, AllowMultiple = true)] +internal sealed class NotNullIfNotNullAttribute : Attribute +{ + /// + /// Gets the associated parameter name. + /// The output will be non- if the argument to the + /// parameter specified is non-. + /// + public string ParameterName { get; } + + /// + /// Initializes the attribute with the associated parameter name. + /// + /// + /// The associated parameter name. + /// The output will be non- if the argument to the + /// parameter specified is non-. + /// + public NotNullIfNotNullAttribute(string parameterName) => + ParameterName = parameterName; +} +#endif \ No newline at end of file diff --git a/src/IpcSample.ConsoleClient/TcpClient.cs b/src/IpcSample.ConsoleClient/TcpClient.cs index 0768ebc6..2d1aa7a4 100644 --- a/src/IpcSample.ConsoleClient/TcpClient.cs +++ b/src/IpcSample.ConsoleClient/TcpClient.cs @@ -1,10 +1,10 @@ using System.Text; using System.Diagnostics; -using UiPath.CoreIpc.Tcp; +using UiPath.Ipc.Tcp; using Microsoft.Extensions.DependencyInjection; using System.Net; -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; class TcpClient { @@ -35,7 +35,7 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken) var serviceProvider = ConfigureServices(); var callback = new ComputingCallback { Id = "custom made" }; var computingClientBuilder = new TcpClientBuilder(SystemEndPoint, serviceProvider) - .SerializeParametersAsObjects().CallbackInstance(callback)/*.EncryptAndSign("localhost")*/.RequestTimeout(TimeSpan.FromSeconds(2)); + .CallbackInstance(callback)/*.EncryptAndSign("localhost")*/.RequestTimeout(TimeSpan.FromSeconds(2)); var stopwatch = Stopwatch.StartNew(); int count = 0; try @@ -43,7 +43,6 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken) var computingClient = computingClientBuilder.ValidateAndBuild(); var systemClient = new TcpClientBuilder(SystemEndPoint) - .SerializeParametersAsObjects() //.EncryptAndSign("localhost") .RequestTimeout(TimeSpan.FromSeconds(2)) .Logger(serviceProvider) diff --git a/src/IpcSample.ConsoleClient/WebSocketClient.cs b/src/IpcSample.ConsoleClient/WebSocketClient.cs index e6c93422..376bd3f1 100644 --- a/src/IpcSample.ConsoleClient/WebSocketClient.cs +++ b/src/IpcSample.ConsoleClient/WebSocketClient.cs @@ -1,8 +1,8 @@ using System.Text; using System.Diagnostics; -using UiPath.CoreIpc.WebSockets; +using UiPath.Ipc.WebSockets; using Microsoft.Extensions.DependencyInjection; -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; class WebSocketClient { static async Task _Main(string[] args) @@ -32,7 +32,7 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken) Uri uri = new("ws://localhost:1212/wsDemo/"); var serviceProvider = ConfigureServices(); var callback = new ComputingCallback { Id = "custom made" }; - var computingClientBuilder = new WebSocketClientBuilder(uri, serviceProvider).SerializeParametersAsObjects() + var computingClientBuilder = new WebSocketClientBuilder(uri, serviceProvider) .CallbackInstance(callback)/*.EncryptAndSign("localhost")*/.RequestTimeout(TimeSpan.FromSeconds(2)); var stopwatch = Stopwatch.StartNew(); int count = 0; @@ -40,7 +40,7 @@ private static async Task RunTestsAsync(CancellationToken cancellationToken) { var computingClient = computingClientBuilder.ValidateAndBuild(); var systemClient = - new WebSocketClientBuilder(uri).SerializeParametersAsObjects() + new WebSocketClientBuilder(uri) //.EncryptAndSign("localhost") .RequestTimeout(TimeSpan.FromSeconds(2)) .Logger(serviceProvider) diff --git a/src/IpcSample.ConsoleServer/IpcSample.ConsoleServer.csproj b/src/IpcSample.ConsoleServer/IpcSample.ConsoleServer.csproj index 2c9744b6..93d37b89 100644 --- a/src/IpcSample.ConsoleServer/IpcSample.ConsoleServer.csproj +++ b/src/IpcSample.ConsoleServer/IpcSample.ConsoleServer.csproj @@ -14,10 +14,10 @@ - - - - + + + + diff --git a/src/IpcSample.ConsoleServer/Server.cs b/src/IpcSample.ConsoleServer/Server.cs index 8e9ad9e4..35f24b8f 100644 --- a/src/IpcSample.ConsoleServer/Server.cs +++ b/src/IpcSample.ConsoleServer/Server.cs @@ -1,8 +1,8 @@ using Microsoft.Extensions.DependencyInjection; using System.Diagnostics; -using UiPath.CoreIpc.NamedPipe; +using UiPath.Ipc.NamedPipe; -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; class Server { diff --git a/src/IpcSample.ConsoleServer/TcpServer.cs b/src/IpcSample.ConsoleServer/TcpServer.cs index 172a7725..9660ec87 100644 --- a/src/IpcSample.ConsoleServer/TcpServer.cs +++ b/src/IpcSample.ConsoleServer/TcpServer.cs @@ -1,9 +1,9 @@ using Microsoft.Extensions.DependencyInjection; using System.Diagnostics; using System.Net; -using UiPath.CoreIpc.Tcp; +using UiPath.Ipc.Tcp; -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; class TcpServer { diff --git a/src/IpcSample.ConsoleServer/WebSocketServer.cs b/src/IpcSample.ConsoleServer/WebSocketServer.cs index 322c1d65..44727483 100644 --- a/src/IpcSample.ConsoleServer/WebSocketServer.cs +++ b/src/IpcSample.ConsoleServer/WebSocketServer.cs @@ -2,8 +2,8 @@ using System.Diagnostics; using System.Net; using System.Net.WebSockets; -using UiPath.CoreIpc.WebSockets; -namespace UiPath.CoreIpc.Tests; +using UiPath.Ipc.WebSockets; +namespace UiPath.Ipc.Tests; class WebSocketServer { //private static readonly Timer _timer = new Timer(_ => diff --git a/src/UiPath.CoreIpc.Tests/ComputingTests.cs b/src/UiPath.CoreIpc.Tests/ComputingTests.cs index 6c562dd9..7cd7c0d5 100644 --- a/src/UiPath.CoreIpc.Tests/ComputingTests.cs +++ b/src/UiPath.CoreIpc.Tests/ComputingTests.cs @@ -1,4 +1,4 @@ -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; public abstract class ComputingTests : TestBase where TBuilder : ServiceClientBuilder { @@ -14,7 +14,7 @@ public ComputingTests() .AddEndpoint() .ValidateAndBuild(); _computingHost.RunAsync(GuiScheduler); - _computingClient = ComputingClientBuilder(GuiScheduler).SerializeParametersAsObjects().ValidateAndBuild(); + _computingClient = ComputingClientBuilder(GuiScheduler).ValidateAndBuild(); } protected abstract TBuilder ComputingClientBuilder(TaskScheduler taskScheduler = null); [Fact] @@ -58,7 +58,7 @@ public async Task ClientCancellation() [Fact] public async Task ClientTimeout() { - var proxy = ComputingClientBuilder().SerializeParametersAsObjects().RequestTimeout(TimeSpan.FromMilliseconds(10)).ValidateAndBuild(); + var proxy = ComputingClientBuilder().RequestTimeout(TimeSpan.FromMilliseconds(10)).ValidateAndBuild(); proxy.Infinite().ShouldThrow().Message.ShouldBe($"{nameof(_computingClient.Infinite)} timed out."); await proxy.GetCallbackThreadName(new Message { RequestTimeout = RequestTimeout }); ((IDisposable)proxy).Dispose(); diff --git a/src/UiPath.CoreIpc.Tests/EndpointTests.cs b/src/UiPath.CoreIpc.Tests/EndpointTests.cs index e62db908..618acf7c 100644 --- a/src/UiPath.CoreIpc.Tests/EndpointTests.cs +++ b/src/UiPath.CoreIpc.Tests/EndpointTests.cs @@ -1,4 +1,4 @@ -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; public class EndpointTests : IDisposable { @@ -34,13 +34,11 @@ private NamedPipeClientBuilder ComputingC .AllowImpersonation() .RequestTimeout(RequestTimeout) .CallbackInstance(_computingCallback) - .SerializeParametersAsObjects() .TaskScheduler(taskScheduler); private ISystemService CreateSystemService() => SystemClientBuilder().ValidateAndBuild(); private NamedPipeClientBuilder SystemClientBuilder() => new NamedPipeClientBuilder(PipeName, _serviceProvider) .CallbackInstance(_systemCallback) - .SerializeParametersAsObjects() .RequestTimeout(RequestTimeout) .AllowImpersonation(); public void Dispose() @@ -66,7 +64,7 @@ public async Task Callback() private async Task CallbackCore() { var proxy = new NamedPipeClientBuilder(PipeName) - .SerializeParametersAsObjects().RequestTimeout(RequestTimeout).AllowImpersonation().ValidateAndBuild(); + .RequestTimeout(RequestTimeout).AllowImpersonation().ValidateAndBuild(); var message = new SystemMessage { Text = Guid.NewGuid().ToString() }; var computingTask = _computingClient.SendMessage(message); var systemTask = _systemClient.SendMessage(message); @@ -89,7 +87,7 @@ public async Task MissingCallback() { exception = ex; } - exception.Message.ShouldBe("Callback contract mismatch. Requested System.IDisposable, but it's UiPath.CoreIpc.Tests.ISystemCallback."); + exception.Message.ShouldBe("Callback contract mismatch. Requested System.IDisposable, but it's UiPath.Ipc.Tests.ISystemCallback."); exception.Is().ShouldBeTrue(); } [Fact] diff --git a/src/UiPath.CoreIpc.Tests/Implementation/ComputingCallback.cs b/src/UiPath.CoreIpc.Tests/Implementation/ComputingCallback.cs index 7938f812..259d5c80 100644 --- a/src/UiPath.CoreIpc.Tests/Implementation/ComputingCallback.cs +++ b/src/UiPath.CoreIpc.Tests/Implementation/ComputingCallback.cs @@ -1,4 +1,4 @@ -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; public interface IComputingCallback { diff --git a/src/UiPath.CoreIpc.Tests/Implementation/ComputingService.cs b/src/UiPath.CoreIpc.Tests/Implementation/ComputingService.cs index 908ee1f0..b52c69b0 100644 --- a/src/UiPath.CoreIpc.Tests/Implementation/ComputingService.cs +++ b/src/UiPath.CoreIpc.Tests/Implementation/ComputingService.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Logging; -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; public interface IInvalid : IDisposable { diff --git a/src/UiPath.CoreIpc.Tests/Implementation/IpcHelpers.cs b/src/UiPath.CoreIpc.Tests/Implementation/IpcHelpers.cs index 41a9292f..b33b54a6 100644 --- a/src/UiPath.CoreIpc.Tests/Implementation/IpcHelpers.cs +++ b/src/UiPath.CoreIpc.Tests/Implementation/IpcHelpers.cs @@ -1,9 +1,9 @@ using Microsoft.Extensions.Logging; using System.Net; using System.Net.WebSockets; -using UiPath.CoreIpc.Tests; +using UiPath.Ipc.Tests; -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; public static class IpcHelpers { diff --git a/src/UiPath.CoreIpc.Tests/Implementation/OneWayStreamWrapper.cs b/src/UiPath.CoreIpc.Tests/Implementation/OneWayStreamWrapper.cs index b63c41c6..1e2bb7b0 100644 --- a/src/UiPath.CoreIpc.Tests/Implementation/OneWayStreamWrapper.cs +++ b/src/UiPath.CoreIpc.Tests/Implementation/OneWayStreamWrapper.cs @@ -1,7 +1,7 @@ // Copyright (c) Andrew Arnott. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; internal class OneWayStreamWrapper : Stream { diff --git a/src/UiPath.CoreIpc.Tests/Implementation/SystemService.cs b/src/UiPath.CoreIpc.Tests/Implementation/SystemService.cs index 049f4e36..5b952638 100644 --- a/src/UiPath.CoreIpc.Tests/Implementation/SystemService.cs +++ b/src/UiPath.CoreIpc.Tests/Implementation/SystemService.cs @@ -1,11 +1,14 @@ using System.Globalization; +using System.IO.Pipes; +using System.Reflection; +using System.Runtime.InteropServices; using System.Text; -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; public interface ISystemService { - Task DoNothing(CancellationToken cancellationToken = default); + Task FireAndForget(CancellationToken cancellationToken = default); Task VoidThreadName(CancellationToken cancellationToken = default); Task VoidSyncThrow(CancellationToken cancellationToken = default); Task GetThreadName(CancellationToken cancellationToken = default); @@ -22,6 +25,8 @@ public interface ISystemService Task Download(string text, CancellationToken cancellationToken = default); Task Echo(Stream input, CancellationToken cancellationToken = default); Task UploadNoRead(Stream memoryStream, int delay = 0, CancellationToken cancellationToken = default); + Task CancelIoPipe(CancelIoPipeMessage message = null, CancellationToken cancellationToken = default); + Task Delay(int delay = 0, CancellationToken cancellationToken = default); } public class SystemMessage : Message @@ -29,6 +34,10 @@ public class SystemMessage : Message public string Text { get; set; } public int Delay { get; set; } } +public class CancelIoPipeMessage : Message +{ + public int[]? MsDelays { get; set; } +} public class SystemService : ISystemService { public SystemService() @@ -66,18 +75,18 @@ public async Task SendMessage(SystemMessage message, CancellationToken c return returnValue; } - public bool DidNothing { get; set; } + public bool FireAndForgetDone { get; set; } - public async Task DoNothing(CancellationToken cancellationToken = default) + public async Task FireAndForget(CancellationToken cancellationToken = default) { const int Timeout = #if CI - 100; + 400; #else - 10; + 40; #endif await Task.Delay(Timeout); - DidNothing = true; + FireAndForgetDone = true; } public async Task GetGuid(Guid guid, CancellationToken cancellationToken = default) @@ -172,4 +181,35 @@ public async Task Echo(Stream input, CancellationToken cancellationToken result.Position = 0; return result; } + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool CancelIoEx(IntPtr handle, IntPtr lpOverlapped); + public async Task CancelIoPipe(CancelIoPipeMessage message = null, CancellationToken cancellationToken = default) + { + Debug.WriteLine("###################### CancelIoPipe"); + await Task.Delay(50); +#if WINDOWS + var serverFieldInfo = message.Client.GetType().GetField("_server", BindingFlags.NonPublic | BindingFlags.Instance); + var pipeStream = serverFieldInfo.GetValue(message.Client) as PipeStream; + + var canceled = CancelIoEx(pipeStream.SafePipeHandle.DangerousGetHandle(), IntPtr.Zero); + + foreach (var msDelay in message.MsDelays ?? []) + { + await Task.Delay(msDelay); + canceled = CancelIoEx(pipeStream.SafePipeHandle.DangerousGetHandle(), IntPtr.Zero); + } + + await Task.Delay(50); + return canceled; +#else + return false; +#endif + } + + public async Task Delay(int delay = 0, CancellationToken cancellationToken = default) + { + await Task.Delay(delay, cancellationToken); + return true; + } } \ No newline at end of file diff --git a/src/UiPath.CoreIpc.Tests/NamedPipeTests.cs b/src/UiPath.CoreIpc.Tests/NamedPipeTests.cs index e81f1eaa..36eb2f23 100644 --- a/src/UiPath.CoreIpc.Tests/NamedPipeTests.cs +++ b/src/UiPath.CoreIpc.Tests/NamedPipeTests.cs @@ -1,19 +1,20 @@ -using System.IO.Pipes; +using System.IO; +using System.IO.Pipes; using System.Security.Principal; -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; public class SystemNamedPipeTests : SystemTests> { string _pipeName = "system"; protected override ServiceHostBuilder Configure(ServiceHostBuilder serviceHostBuilder) => - serviceHostBuilder.UseNamedPipes(Configure(new NamedPipeSettings(_pipeName+GetHashCode()))); - protected override NamedPipeClientBuilder CreateSystemClientBuilder() => - new NamedPipeClientBuilder(_pipeName+GetHashCode()).AllowImpersonation(); + serviceHostBuilder.UseNamedPipes(Configure(new NamedPipeSettings(_pipeName + GetHashCode()))); + protected override NamedPipeClientBuilder CreateSystemClientBuilder() => + new NamedPipeClientBuilder(_pipeName + GetHashCode()).AllowImpersonation(); [Fact] public void PipeExists() { IOHelpers.PipeExists(System.Guid.NewGuid().ToString()).ShouldBeFalse(); - IOHelpers.PipeExists("system"+GetHashCode(), 50).ShouldBeTrue(); + IOHelpers.PipeExists("system" + GetHashCode(), 50).ShouldBeTrue(); } [Fact] public Task ServerName() => SystemClientBuilder().ValidateAndBuild().GetGuid(System.Guid.Empty); @@ -36,7 +37,42 @@ public async Task PipeSecurityForWindows() .AddEndpoint() .ValidateAndBuild(); _ = protectedService.RunAsync(); - await CreateSystemService().DoNothing().ShouldThrowAsync(); + await CreateSystemService().FireAndForget().ShouldThrowAsync(); + } + + [Theory] + [InlineData(new int[0])] + [InlineData(100)] + [InlineData(1100)] + [InlineData(100, 100)] + public async Task PipeCancelIoOnServer_AnyNoOfTimes(params int[] msDelays) + { + bool cancelIoResult = false; + + // Any number of kernel32.CancelIoEx calls should not cause the client to give up on the connection. + var act = async () => cancelIoResult = await _systemClient.CancelIoPipe(new() { MsDelays = msDelays }); + await act.ShouldNotThrowAsync(); + + //Make sure the connection is still working + (await _systemClient.Delay()).ShouldBeTrue(); + + cancelIoResult.ShouldBeTrue(); + } + + [Fact] + public async Task PipeCancelIoOnClient() + { + (await _systemClient.Delay()).ShouldBeTrue(); + + var delayTask = _systemClient.Delay(500); + await Task.Delay(100); + var pipeStream = ((IpcProxy)_systemClient).Connection.Network as PipeStream; + SystemService.CancelIoEx(pipeStream.SafePipeHandle.DangerousGetHandle(), IntPtr.Zero).ShouldBeTrue(); + + (await delayTask).ShouldBeTrue(); + + //Make sure the connection is still working + (await _systemClient.Delay()).ShouldBeTrue(); } #endif } diff --git a/src/UiPath.CoreIpc.Tests/NestedStreamTests.cs b/src/UiPath.CoreIpc.Tests/NestedStreamTests.cs index b30d6f93..a96af00a 100644 --- a/src/UiPath.CoreIpc.Tests/NestedStreamTests.cs +++ b/src/UiPath.CoreIpc.Tests/NestedStreamTests.cs @@ -1,6 +1,6 @@ using System.IO.Compression; -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; public class NestedStreamTests { @@ -358,7 +358,7 @@ public async Task ReadAsync_ValidatesArguments() await Assert.ThrowsAsync(() => this.stream.ReadAsync(buffer, 1, buffer.Length)); } } -public static class StreamExtensions +internal static class StreamExtensions { /// /// Creates a that can read no more than a given number of bytes from an underlying stream. diff --git a/src/UiPath.CoreIpc.Tests/SystemTests.cs b/src/UiPath.CoreIpc.Tests/SystemTests.cs index e33832f4..232c1ac4 100644 --- a/src/UiPath.CoreIpc.Tests/SystemTests.cs +++ b/src/UiPath.CoreIpc.Tests/SystemTests.cs @@ -1,11 +1,11 @@ using System.Text; -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; public abstract class SystemTests : TestBase where TBuilder : ServiceClientBuilder { protected ServiceHost _systemHost; - protected ISystemService _systemClient; + protected readonly ISystemService _systemClient; protected readonly SystemService _systemService; public SystemTests() { @@ -55,10 +55,10 @@ public async Task ServerTimeout() [Fact] public async Task Void() { - _systemService.DidNothing = false; - await _systemClient.DoNothing(); - _systemService.DidNothing.ShouldBeFalse(); - while (!_systemService.DidNothing) + _systemService.FireAndForgetDone = false; + await _systemClient.FireAndForget(); + _systemService.FireAndForgetDone.ShouldBeFalse(); + while (!_systemService.FireAndForgetDone) { await Task.Delay(10); Trace.WriteLine(this + " Void"); @@ -194,7 +194,7 @@ public async Task DownloadNoRead() await Guid(); } protected abstract TBuilder CreateSystemClientBuilder(); - protected TBuilder SystemClientBuilder() => CreateSystemClientBuilder().SerializeParametersAsObjects().RequestTimeout(RequestTimeout).Logger(_serviceProvider); + protected TBuilder SystemClientBuilder() => CreateSystemClientBuilder().RequestTimeout(RequestTimeout).Logger(_serviceProvider); [Fact] public async Task BeforeCall() { @@ -202,15 +202,15 @@ public async Task BeforeCall() var proxy = SystemClientBuilder().BeforeCall(async (c, _) => { newConnection = c.NewConnection; - c.Method.ShouldBe(typeof(ISystemService).GetMethod(nameof(ISystemService.DoNothing))); + c.Method.ShouldBe(typeof(ISystemService).GetMethod(nameof(ISystemService.FireAndForget))); c.Arguments.Single().ShouldBe(""); // cancellation token }).ValidateAndBuild(); newConnection.ShouldBeFalse(); - await proxy.DoNothing(); + await proxy.FireAndForget(); newConnection.ShouldBeTrue(); - await proxy.DoNothing(); + await proxy.FireAndForget(); newConnection.ShouldBeFalse(); var ipcProxy = (IpcProxy)proxy; var closed = false; @@ -218,10 +218,10 @@ public async Task BeforeCall() ipcProxy.CloseConnection(); closed.ShouldBeTrue(); newConnection.ShouldBeFalse(); - await proxy.DoNothing(); + await proxy.FireAndForget(); newConnection.ShouldBeTrue(); - await proxy.DoNothing(); + await proxy.FireAndForget(); newConnection.ShouldBeFalse(); ipcProxy.CloseConnection(); } diff --git a/src/UiPath.CoreIpc.Tests/TcpTests..cs b/src/UiPath.CoreIpc.Tests/TcpTests..cs index cca919c5..9519b1aa 100644 --- a/src/UiPath.CoreIpc.Tests/TcpTests..cs +++ b/src/UiPath.CoreIpc.Tests/TcpTests..cs @@ -1,6 +1,6 @@ using System.Net; -using UiPath.CoreIpc.Tcp; -namespace UiPath.CoreIpc.Tests; +using UiPath.Ipc.Tcp; +namespace UiPath.Ipc.Tests; public class SystemTcpTests : SystemTests> { int _port = 3131 + GetCount(); diff --git a/src/UiPath.CoreIpc.Tests/TestBase.cs b/src/UiPath.CoreIpc.Tests/TestBase.cs index 98d75a4e..b38fb183 100644 --- a/src/UiPath.CoreIpc.Tests/TestBase.cs +++ b/src/UiPath.CoreIpc.Tests/TestBase.cs @@ -1,6 +1,6 @@ using Nito.AsyncEx; -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; public abstract class TestBase : IDisposable { @@ -8,9 +8,10 @@ public abstract class TestBase : IDisposable protected static int Count = -1; public static readonly TimeSpan RequestTimeout = #if CI - TimeSpan.FromSeconds(2) + + TimeSpan.FromSeconds(3) + #endif - (Debugger.IsAttached ? TimeSpan.FromDays(1) : TimeSpan.FromSeconds(2)); + TimeSpan.FromSeconds(3); + // (Debugger.IsAttached ? TimeSpan.FromDays(1) : TimeSpan.FromSeconds(2)); protected readonly IServiceProvider _serviceProvider; protected readonly AsyncContext _guiThread = new AsyncContextThread().Context; diff --git a/src/UiPath.CoreIpc.Tests/UiPath.CoreIpc.Tests.csproj b/src/UiPath.CoreIpc.Tests/UiPath.CoreIpc.Tests.csproj index eaf03da6..5b773092 100644 --- a/src/UiPath.CoreIpc.Tests/UiPath.CoreIpc.Tests.csproj +++ b/src/UiPath.CoreIpc.Tests/UiPath.CoreIpc.Tests.csproj @@ -2,17 +2,19 @@ net6.0;net461;net6.0-windows + UiPath.Ipc.Tests $(NoWarn);1998 $(DefineConstants);$(DefineConstantsEx) latest true + annotations - - - + + + @@ -25,6 +27,6 @@ - + \ No newline at end of file diff --git a/src/UiPath.CoreIpc.Tests/ValidationTests.cs b/src/UiPath.CoreIpc.Tests/ValidationTests.cs index a1a0197c..543c4194 100644 --- a/src/UiPath.CoreIpc.Tests/ValidationTests.cs +++ b/src/UiPath.CoreIpc.Tests/ValidationTests.cs @@ -1,4 +1,4 @@ -namespace UiPath.CoreIpc.Tests; +namespace UiPath.Ipc.Tests; public class ValidationTests { diff --git a/src/UiPath.CoreIpc.Tests/WebSocketTests.cs b/src/UiPath.CoreIpc.Tests/WebSocketTests.cs index 0661160c..ad1e920d 100644 --- a/src/UiPath.CoreIpc.Tests/WebSocketTests.cs +++ b/src/UiPath.CoreIpc.Tests/WebSocketTests.cs @@ -1,8 +1,8 @@ -using UiPath.CoreIpc.WebSockets; -namespace UiPath.CoreIpc.Tests; +using UiPath.Ipc.WebSockets; +namespace UiPath.Ipc.Tests; public class SystemWebSocketTests : SystemTests> { - int _port = 1313 + GetCount(); + int _port = 51313 + GetCount(); HttpSysWebSocketsListener _listener; protected override ServiceHostBuilder Configure(ServiceHostBuilder serviceHostBuilder) { diff --git a/src/UiPath.CoreIpc/CancellationTokenSourcePool.cs b/src/UiPath.CoreIpc/CancellationTokenSourcePool.cs index a6d0b3f8..0d517d86 100644 --- a/src/UiPath.CoreIpc/CancellationTokenSourcePool.cs +++ b/src/UiPath.CoreIpc/CancellationTokenSourcePool.cs @@ -1,4 +1,4 @@ -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; // https://github.com/dotnet/aspnetcore/blob/main/src/Shared/CancellationTokenSourcePool.cs internal static class CancellationTokenSourcePool { diff --git a/src/UiPath.CoreIpc/Client/ClientConnectionsRegistry.cs b/src/UiPath.CoreIpc/Client/ClientConnectionsRegistry.cs index 14b708fc..9f5bcc70 100644 --- a/src/UiPath.CoreIpc/Client/ClientConnectionsRegistry.cs +++ b/src/UiPath.CoreIpc/Client/ClientConnectionsRegistry.cs @@ -1,4 +1,4 @@ -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; static class ClientConnectionsRegistry { @@ -35,7 +35,6 @@ internal static ClientConnection Remove(IConnectionKey connectionKey) } interface IConnectionKey : IEquatable { - string SslServer { get; } ClientConnection CreateClientConnection(); } abstract class ClientConnection : IDisposable diff --git a/src/UiPath.CoreIpc/Client/ServiceClient.cs b/src/UiPath.CoreIpc/Client/ServiceClient.cs index 8ee847f5..2561d267 100644 --- a/src/UiPath.CoreIpc/Client/ServiceClient.cs +++ b/src/UiPath.CoreIpc/Client/ServiceClient.cs @@ -1,5 +1,4 @@ -using System.Net.Security; -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; using ConnectionFactory = Func>; using BeforeCallHandler = Func; @@ -24,23 +23,19 @@ class ServiceClient : IServiceClient, IConnectionKey where TInterfac private Server _server; private ClientConnection _clientConnection; - internal ServiceClient(ISerializer serializer, TimeSpan requestTimeout, ILogger logger, ConnectionFactory connectionFactory, string sslServer = null, BeforeCallHandler beforeCall = null, bool objectParameters = false, EndpointSettings serviceEndpoint = null) + internal ServiceClient(ISerializer serializer, TimeSpan requestTimeout, ILogger logger, ConnectionFactory connectionFactory, BeforeCallHandler beforeCall = null, EndpointSettings serviceEndpoint = null) { - ObjectParameters = objectParameters; _serializer = serializer; _requestTimeout = requestTimeout; _logger = logger; _connectionFactory = connectionFactory; - SslServer = sslServer; _beforeCall = beforeCall; _serviceEndpoint = serviceEndpoint; } protected int HashCode { get; init; } - public string SslServer { get; init; } public virtual string Name => _connection?.Name; private bool LogEnabled => _logger.Enabled(); Connection IServiceClient.Connection => _connection; - public bool ObjectParameters { get; init; } public TInterface CreateProxy() { @@ -48,7 +43,7 @@ public TInterface CreateProxy() (proxy as IpcProxy).ServiceClient = this; return proxy; } - + public override int GetHashCode() => HashCode; private void OnNewConnection(Connection connection, bool alreadyHasServer = false) @@ -98,7 +93,7 @@ async Task Invoke() await _beforeCall(new(newConnection, method, args), token); } var requestId = _connection.NewRequestId(); - var request = new Request(typeof(TInterface).Name, requestId, methodName, serializedArguments, ObjectParameters ? args : null, messageTimeout.TotalSeconds) + var request = new Request(typeof(TInterface).Name, requestId, methodName, serializedArguments, messageTimeout.TotalSeconds) { UploadStream = uploadStream }; @@ -106,17 +101,12 @@ async Task Invoke() { Log($"IpcClient calling {methodName} {requestId} {Name}."); } - if (ObjectParameters && !method.ReturnType.IsGenericType) - { - await _connection.Send(request, token); - return default; - } var response = await _connection.RemoteCall(request, token); if (LogEnabled) { Log($"IpcClient called {methodName} {requestId} {Name}."); } - return response.Deserialize(_serializer, ObjectParameters); + return response.Deserialize(_serializer); } catch (Exception ex) { @@ -129,10 +119,8 @@ async Task Invoke() } void SerializeArguments() { - if (!ObjectParameters) - { - serializedArguments = new string[args.Length]; - } + serializedArguments = new string[args.Length]; + for (int index = 0; index < args.Length; index++) { switch (args[index]) @@ -150,10 +138,8 @@ void SerializeArguments() args[index] = ""; break; } - if (!ObjectParameters) - { - serializedArguments[index] = _serializer.Serialize(args[index]); - } + + serializedArguments[index] = _serializer.Serialize(args[index]); } } } @@ -201,9 +187,8 @@ private async Task Connect(CancellationToken cancellationToken) { clientConnection.Dispose(); throw; - } - var stream = SslServer == null ? network : await AuthenticateAsClient(network); - OnNewConnection(new(stream, _serializer, _logger, Name)); + } + OnNewConnection(new(network, _serializer, _logger, Name)); if (LogEnabled) { Log($"CreateConnection {Name}."); @@ -215,21 +200,6 @@ private async Task Connect(CancellationToken cancellationToken) clientConnection.Release(); } return true; - async Task AuthenticateAsClient(Stream network) - { - var sslStream = new SslStream(network); - try - { - await sslStream.AuthenticateAsClientAsync(SslServer); - } - catch - { - sslStream.Dispose(); - throw; - } - Debug.Assert(sslStream.IsEncrypted && sslStream.IsSigned); - return sslStream; - } } private void ReuseClientConnection(ClientConnection clientConnection) @@ -287,7 +257,7 @@ protected virtual void Dispose(bool disposing) public override string ToString() => Name; - public virtual bool Equals(IConnectionKey other) => SslServer == other.SslServer; + public virtual bool Equals(IConnectionKey other) => true; public virtual ClientConnection CreateClientConnection() => throw new NotImplementedException(); } diff --git a/src/UiPath.CoreIpc/Client/ServiceClientBuilder.cs b/src/UiPath.CoreIpc/Client/ServiceClientBuilder.cs index db59c9f7..afbf26e8 100644 --- a/src/UiPath.CoreIpc/Client/ServiceClientBuilder.cs +++ b/src/UiPath.CoreIpc/Client/ServiceClientBuilder.cs @@ -1,4 +1,4 @@ -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; using ConnectionFactory = Func>; using BeforeCallHandler = Func; @@ -13,8 +13,6 @@ public abstract class ServiceClientBuilder where TInterfac protected BeforeCallHandler _beforeCall; protected object _callbackInstance; protected TaskScheduler _taskScheduler; - protected string _sslServer; - protected bool _objectParameters; protected ServiceClientBuilder(Type callbackContract, IServiceProvider serviceProvider) { @@ -32,16 +30,6 @@ public TDerived ConnectionFactory(ConnectionFactory connectionFactory) return (TDerived)this; } - public TDerived EncryptAndSign(string certificateServerName) - { - if (string.IsNullOrWhiteSpace(certificateServerName)) - { - throw new ArgumentException($"'{nameof(certificateServerName)}' must match the name on the server's certificate.", nameof(certificateServerName)); - } - _sslServer = certificateServerName; - return (TDerived)this; - } - public TDerived BeforeCall(BeforeCallHandler beforeCall) { _beforeCall = beforeCall; @@ -53,18 +41,6 @@ public TDerived Logger(ILogger logger) _logger = logger; return (TDerived)this; } - /// - /// By default, method parameters are serialized as json strings. Setting this allows serialization as json objects. - /// This should improve performance for large strings, but decrease it for many small objects. - /// Setting it breaks compatibility with older servers. - /// So a proxy with this setting will only be able to connect to servers that understand the new encoding. - /// - /// this - public TDerived SerializeParametersAsObjects() - { - _objectParameters = true; - return (TDerived)this; - } public TDerived Logger(IServiceProvider serviceProvider) => Logger(serviceProvider.GetRequiredService>()); diff --git a/src/UiPath.CoreIpc/Connection.cs b/src/UiPath.CoreIpc/Connection.cs index e4404147..f5c59229 100644 --- a/src/UiPath.CoreIpc/Connection.cs +++ b/src/UiPath.CoreIpc/Connection.cs @@ -1,6 +1,11 @@ -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; using static TaskCompletionPool; using static IOHelpers; +using System.IO.Pipes; +using System.IO; +using System.Threading; +using Microsoft.Extensions.Logging; + public sealed class Connection : IDisposable { private static readonly IOException ClosedException = new("Connection closed."); @@ -75,7 +80,6 @@ internal async ValueTask RemoteCall(Request request, CancellationToken } internal ValueTask Send(Request request, CancellationToken token) { - Debug.Assert(request.Parameters == null || request.ObjectParameters == null); var uploadStream = request.UploadStream; var requestBytes = SerializeToStream(request); return uploadStream == null ? @@ -95,7 +99,6 @@ Task CancelServerCall(string requestId) => } internal ValueTask Send(Response response, CancellationToken cancellationToken) { - Debug.Assert(response.Data == null || response.ObjectData == null); var responseBytes = SerializeToStream(response); return response.DownloadStream == null ? SendMessage(MessageType.Response, responseBytes, cancellationToken) : @@ -183,14 +186,32 @@ private async ValueTask ReadBuffer(int length) { int offset = 0; int toRead = length; + do { - var read = await Network.ReadAsync( + int read; + try + { + read = await Network.ReadAsync( #if NET461 - _buffer, offset, toRead); + _buffer, offset, toRead); #else - _buffer.AsMemory(offset, toRead)); + _buffer.AsMemory(offset, toRead)); #endif + } + catch (OperationCanceledException ex) when (Network is PipeStream) + { + // Originally we decided to throw this exception the 2nd time we caught it, but later it was discovered that the NodeJS runtime continuosly retries. + + // In some Windows client environments, OperationCanceledException is sporadically thrown on named pipe ReadAsync operation (ERROR_OPERATION_ABORTED on overlapped ReadFile) + // The cause has not yet been discovered(os specific, antiviruses, monitoring application), and we have implemented a retry system + // ROBO-3083 + + Logger.LogException(ex, $"Retrying ReadAsync for {Network.GetType()}"); + await Task.Delay(10); //Without this delay, on net framework can get OperationCanceledException on the second ReadAsync call + continue; + } + if (read == 0) { return false; @@ -319,7 +340,7 @@ private void OnCancellationReceived(string requestId) { CancellationReceived(requestId); } - catch(Exception ex) + catch (Exception ex) { Log(ex); } diff --git a/src/UiPath.CoreIpc/Dtos.cs b/src/UiPath.CoreIpc/Dtos.cs index cbf278ba..ea7e66a8 100644 --- a/src/UiPath.CoreIpc/Dtos.cs +++ b/src/UiPath.CoreIpc/Dtos.cs @@ -1,16 +1,16 @@ -using System.Text; +using System.Diagnostics.CodeAnalysis; +using System.Text; using Newtonsoft.Json; -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; public class Message { - internal bool ObjectParameters { get; set; } internal Type CallbackContract { get; set; } [JsonIgnore] public IClient Client { get; set; } [JsonIgnore] public TimeSpan RequestTimeout { get; set; } public TCallbackInterface GetCallback() where TCallbackInterface : class => - Client.GetCallback(CallbackContract, ObjectParameters); + Client.GetCallback(CallbackContract); public void ImpersonateClient(Action action) => Client.Impersonate(action); } public class Message : Message @@ -18,34 +18,43 @@ public class Message : Message public Message(TPayload payload) => Payload = payload; public TPayload Payload { get; } } -record Request(string Endpoint, string Id, string MethodName, string[] Parameters, object[] ObjectParameters, double TimeoutInSeconds) +record Request(string Endpoint, string Id, string MethodName, string[] Parameters, double TimeoutInSeconds) { internal Stream UploadStream { get; set; } public override string ToString() => $"{Endpoint} {MethodName} {Id}."; - internal bool HasObjectParameters => ObjectParameters is not null; internal TimeSpan GetTimeout(TimeSpan defaultTimeout) => TimeoutInSeconds == 0 ? defaultTimeout : TimeSpan.FromSeconds(TimeoutInSeconds); } record CancellationRequest(string RequestId); -record Response(string RequestId, string Data = null, object ObjectData = null, Error Error = null) +record Response(string RequestId, string Data = null, Error Error = null) { internal Stream DownloadStream { get; set; } public static Response Fail(Request request, Exception ex) => new(request.Id, Error: ex.ToError()); public static Response Success(Request request, string data) => new(request.Id, data); public static Response Success(Request request, Stream downloadStream) => new(request.Id) { DownloadStream = downloadStream }; - public TResult Deserialize(ISerializer serializer, bool objectParameters) + public TResult Deserialize(ISerializer serializer) { if (Error != null) { throw new RemoteException(Error); } - return (TResult)(DownloadStream ?? (objectParameters ? - serializer.Deserialize(ObjectData, typeof(TResult)) : serializer.Deserialize(Data ?? "", typeof(TResult)))); + return (TResult)(DownloadStream ?? serializer.Deserialize(Data ?? "", typeof(TResult))); } } [Serializable] public record Error(string Message, string StackTrace, string Type, Error InnerError) { + [return: NotNullIfNotNull("exception")] + public static Error? FromException(Exception? exception) + => exception is null + ? null + : new( + Message: exception.Message, + StackTrace: exception.StackTrace ?? exception.GetBaseException().StackTrace, + Type: GetExceptionType(exception), + InnerError: FromException(exception.InnerException)); public override string ToString() => new RemoteException(this).ToString(); + + private static string GetExceptionType(Exception exception) => (exception as RemoteException)?.Type ?? exception.GetType().FullName; } [Serializable] public class RemoteException : Exception diff --git a/src/UiPath.CoreIpc/Helpers.cs b/src/UiPath.CoreIpc/Helpers.cs index 58c39029..65918e0e 100644 --- a/src/UiPath.CoreIpc/Helpers.cs +++ b/src/UiPath.CoreIpc/Helpers.cs @@ -6,7 +6,7 @@ using System.Runtime.InteropServices; using System.Security.AccessControl; using System.Security.Principal; -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; using static CancellationTokenSourcePool; public static class Helpers { @@ -19,13 +19,13 @@ public static async Task ConnectAsync(this TcpClient tcpClient, IPAddress addres await tcpClient.ConnectAsync(address, port); } #endif - public static Error ToError(this Exception ex) => new(ex.Message, ex.StackTrace ?? ex.GetBaseException().StackTrace, GetExceptionType(ex), ex.InnerException?.ToError()); + internal static Error ToError(this Exception ex) => new(ex.Message, ex.StackTrace ?? ex.GetBaseException().StackTrace, GetExceptionType(ex), ex.InnerException?.ToError()); private static string GetExceptionType(Exception exception) => (exception as RemoteException)?.Type ?? exception.GetType().FullName; - public static bool Enabled(this ILogger logger) => logger != null && logger.IsEnabled(LogLevel.Information); + internal static bool Enabled(this ILogger logger) => logger != null && logger.IsEnabled(LogLevel.Information); [Conditional("DEBUG")] - public static void AssertDisposed(this SemaphoreSlim semaphore) => semaphore.AssertFieldNull("m_waitHandle"); + internal static void AssertDisposed(this SemaphoreSlim semaphore) => semaphore.AssertFieldNull("m_waitHandle"); [Conditional("DEBUG")] - public static void AssertDisposed(this CancellationTokenSource cts) + internal static void AssertDisposed(this CancellationTokenSource cts) { #if NET461 cts.AssertFieldNull("m_kernelEvent"); @@ -38,10 +38,10 @@ public static void AssertDisposed(this CancellationTokenSource cts) [Conditional("DEBUG")] static void AssertFieldNull(this object obj, string field) => Debug.Assert(obj.GetType().GetField(field, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj) == null); - public static TDelegate MakeGenericDelegate(this MethodInfo genericMethod, Type genericArgument) where TDelegate : Delegate => + internal static TDelegate MakeGenericDelegate(this MethodInfo genericMethod, Type genericArgument) where TDelegate : Delegate => (TDelegate)genericMethod.MakeGenericMethod(genericArgument).CreateDelegate(typeof(TDelegate)); - public static MethodInfo GetStaticMethod(this Type type, string name) => type.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic); - public static MethodInfo GetInterfaceMethod(this Type type, string name) + internal static MethodInfo GetStaticMethod(this Type type, string name) => type.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic); + internal static MethodInfo GetInterfaceMethod(this Type type, string name) { var method = type.GetMethod(name, InstanceFlags) ?? type.GetInterfaces().Select(t => t.GetMethod(name, InstanceFlags)).FirstOrDefault(m => m != null) ?? @@ -52,15 +52,15 @@ public static MethodInfo GetInterfaceMethod(this Type type, string name) } return method; } - public static IEnumerable GetInterfaceMethods(this Type type) => + internal static IEnumerable GetInterfaceMethods(this Type type) => type.GetMethods().Concat(type.GetInterfaces().SelectMany(i => i.GetMethods())); - public static object GetDefaultValue(this ParameterInfo parameter) => parameter switch + internal static object GetDefaultValue(this ParameterInfo parameter) => parameter switch { { HasDefaultValue: false } => null, { ParameterType: { IsValueType: true }, DefaultValue: null } => Activator.CreateInstance(parameter.ParameterType), _ => parameter.DefaultValue }; - public static ReadOnlyDictionary ToReadOnlyDictionary(this IDictionary dictionary) => new(dictionary); + internal static ReadOnlyDictionary ToReadOnlyDictionary(this IDictionary dictionary) => new(dictionary); public static void LogException(this ILogger logger, Exception ex, object tag) { var message = $"{tag} # {ex}"; @@ -167,7 +167,7 @@ private static async ValueTask WriteMessageCore(this Stream stream, RecyclableMe internal static Task WriteBuffer(this Stream stream, byte[] buffer, CancellationToken cancellationToken) => stream.WriteAsync(buffer, 0, buffer.Length, cancellationToken); } -public static class Validator +internal static class Validator { public static void Validate(ServiceHostBuilder serviceHostBuilder) { @@ -267,7 +267,7 @@ private static void CheckDerivedStream(MethodInfo method, Type type) } } } -public readonly struct TimeoutHelper : IDisposable +internal readonly struct TimeoutHelper : IDisposable { private static readonly Action LinkedTokenCancelDelegate = static s => ((CancellationTokenSource)s).Cancel(); private readonly PooledCancellationTokenSource _timeoutCancellationSource; diff --git a/src/UiPath.CoreIpc/IpcJsonSerializer.cs b/src/UiPath.CoreIpc/IpcJsonSerializer.cs index 33a9faf5..0536cb55 100644 --- a/src/UiPath.CoreIpc/IpcJsonSerializer.cs +++ b/src/UiPath.CoreIpc/IpcJsonSerializer.cs @@ -3,20 +3,18 @@ using System.Buffers; using System.Globalization; using System.Text; -namespace UiPath.CoreIpc; + +namespace UiPath.Ipc; public interface ISerializer { ValueTask DeserializeAsync(Stream json); - object Deserialize(object json, Type type); void Serialize(object obj, Stream stream); string Serialize(object obj); object Deserialize(string json, Type type); } class IpcJsonSerializer : ISerializer, IArrayPool { - static readonly JsonSerializer ObjectArgsSerializer = new(){ DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, NullValueHandling = NullValueHandling.Ignore, - CheckAdditionalContent = true }; static readonly JsonSerializer StringArgsSerializer = new(){ CheckAdditionalContent = true }; #if !NET461 [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] @@ -27,15 +25,9 @@ public async ValueTask DeserializeAsync(Stream json) await json.CopyToAsync(stream); stream.Position = 0; using var reader = CreateReader(new StreamReader(stream)); - return ObjectArgsSerializer.Deserialize(reader); + return StringArgsSerializer.Deserialize(reader); } - public object Deserialize(object json, Type type) => json switch - { - JToken token => token.ToObject(type, ObjectArgsSerializer), - { } => type.IsAssignableFrom(json.GetType()) ? json : new JValue(json).ToObject(type), - null => null, - }; - public void Serialize(object obj, Stream stream) => Serialize(obj, new StreamWriter(stream), ObjectArgsSerializer); + public void Serialize(object obj, Stream stream) => Serialize(obj, new StreamWriter(stream), StringArgsSerializer); private void Serialize(object obj, TextWriter streamWriter, JsonSerializer serializer) { using var writer = new JsonTextWriter(streamWriter) { ArrayPool = this, CloseOutput = false }; diff --git a/src/UiPath.CoreIpc/NamedPipe/NamedPipeClient.cs b/src/UiPath.CoreIpc/NamedPipe/NamedPipeClient.cs index 61584f39..e6b7bad4 100644 --- a/src/UiPath.CoreIpc/NamedPipe/NamedPipeClient.cs +++ b/src/UiPath.CoreIpc/NamedPipe/NamedPipeClient.cs @@ -1,7 +1,7 @@ using System.IO.Pipes; using System.Security.Principal; -namespace UiPath.CoreIpc.NamedPipe; +namespace UiPath.Ipc.NamedPipe; using ConnectionFactory = Func>; using BeforeCallHandler = Func; @@ -15,13 +15,13 @@ interface INamedPipeKey : IConnectionKey class NamedPipeClient : ServiceClient, INamedPipeKey where TInterface : class { - public NamedPipeClient(string serverName, string pipeName, ISerializer serializer, TimeSpan requestTimeout, bool allowImpersonation, ILogger logger, ConnectionFactory connectionFactory, string sslServer, BeforeCallHandler beforeCall, bool objectParameters, EndpointSettings serviceEndpoint) - : base(serializer, requestTimeout, logger, connectionFactory, sslServer, beforeCall, objectParameters, serviceEndpoint) + public NamedPipeClient(string serverName, string pipeName, ISerializer serializer, TimeSpan requestTimeout, bool allowImpersonation, ILogger logger, ConnectionFactory connectionFactory, BeforeCallHandler beforeCall, EndpointSettings serviceEndpoint) + : base(serializer, requestTimeout, logger, connectionFactory, beforeCall, serviceEndpoint) { ServerName = serverName; PipeName = pipeName; AllowImpersonation = allowImpersonation; - HashCode = (serverName, pipeName, allowImpersonation, sslServer).GetHashCode(); + HashCode = (serverName, pipeName, allowImpersonation).GetHashCode(); } public override string Name => base.Name ?? PipeName; public string ServerName { get; } diff --git a/src/UiPath.CoreIpc/NamedPipe/NamedPipeClientBuilder.cs b/src/UiPath.CoreIpc/NamedPipe/NamedPipeClientBuilder.cs index 5e4b69d4..1241b8f9 100644 --- a/src/UiPath.CoreIpc/NamedPipe/NamedPipeClientBuilder.cs +++ b/src/UiPath.CoreIpc/NamedPipe/NamedPipeClientBuilder.cs @@ -1,4 +1,4 @@ -namespace UiPath.CoreIpc.NamedPipe; +namespace UiPath.Ipc.NamedPipe; public abstract class NamedPipeClientBuilderBase : ServiceClientBuilder where TInterface : class where TDerived : ServiceClientBuilder { @@ -27,7 +27,7 @@ public TDerived AllowImpersonation() } protected override TInterface BuildCore(EndpointSettings serviceEndpoint) => - new NamedPipeClient(_serverName, _pipeName, _serializer, _requestTimeout, _allowImpersonation, _logger, _connectionFactory, _sslServer, _beforeCall, _objectParameters, serviceEndpoint).CreateProxy(); + new NamedPipeClient(_serverName, _pipeName, _serializer, _requestTimeout, _allowImpersonation, _logger, _connectionFactory, _beforeCall, serviceEndpoint).CreateProxy(); } public class NamedPipeClientBuilder : NamedPipeClientBuilderBase, TInterface> where TInterface : class diff --git a/src/UiPath.CoreIpc/NamedPipe/NamedPipeListener.cs b/src/UiPath.CoreIpc/NamedPipe/NamedPipeListener.cs index 5f408757..fa9515fa 100644 --- a/src/UiPath.CoreIpc/NamedPipe/NamedPipeListener.cs +++ b/src/UiPath.CoreIpc/NamedPipe/NamedPipeListener.cs @@ -1,7 +1,7 @@ using System.IO.Pipes; using System.Security.Principal; -namespace UiPath.CoreIpc.NamedPipe; +namespace UiPath.Ipc.NamedPipe; public class NamedPipeSettings : ListenerSettings { diff --git a/src/UiPath.CoreIpc/NestedStream.cs b/src/UiPath.CoreIpc/NestedStream.cs index fdc40877..2e69166e 100644 --- a/src/UiPath.CoreIpc/NestedStream.cs +++ b/src/UiPath.CoreIpc/NestedStream.cs @@ -1,10 +1,10 @@ -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; /// /// A stream that allows for reading from another stream up to a given number of bytes. /// https://github.com/AArnott/Nerdbank.Streams/blob/3303c541c29b979f61c86c3c2ed5c0e7372d7a55/src/Nerdbank.Streams/NestedStream.cs#L18 /// -public class NestedStream : Stream +internal class NestedStream : Stream { /// /// The stream to read from. diff --git a/src/UiPath.CoreIpc/Polyfills/NotNullIfNotNullAttribute.cs b/src/UiPath.CoreIpc/Polyfills/NotNullIfNotNullAttribute.cs new file mode 100644 index 00000000..3f9caea2 --- /dev/null +++ b/src/UiPath.CoreIpc/Polyfills/NotNullIfNotNullAttribute.cs @@ -0,0 +1,30 @@ +#if NETFRAMEWORK + +namespace System.Diagnostics.CodeAnalysis; + +using static AttributeTargets; + +[ExcludeFromCodeCoverage] +[DebuggerNonUserCode] +[AttributeUsage(Parameter | Property | ReturnValue, AllowMultiple = true)] +internal sealed class NotNullIfNotNullAttribute : Attribute +{ + /// + /// Gets the associated parameter name. + /// The output will be non- if the argument to the + /// parameter specified is non-. + /// + public string ParameterName { get; } + + /// + /// Initializes the attribute with the associated parameter name. + /// + /// + /// The associated parameter name. + /// The output will be non- if the argument to the + /// parameter specified is non-. + /// + public NotNullIfNotNullAttribute(string parameterName) => + ParameterName = parameterName; +} +#endif \ No newline at end of file diff --git a/src/UiPath.CoreIpc/Server/Listener.cs b/src/UiPath.CoreIpc/Server/Listener.cs index a9c10adf..ef156c2b 100644 --- a/src/UiPath.CoreIpc/Server/Listener.cs +++ b/src/UiPath.CoreIpc/Server/Listener.cs @@ -1,6 +1,6 @@ using System.Security.Cryptography.X509Certificates; -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; public class ListenerSettings { diff --git a/src/UiPath.CoreIpc/Server/Server.cs b/src/UiPath.CoreIpc/Server/Server.cs index 5e6d5b4d..f8e25f32 100644 --- a/src/UiPath.CoreIpc/Server/Server.cs +++ b/src/UiPath.CoreIpc/Server/Server.cs @@ -1,5 +1,5 @@ using System.Linq.Expressions; -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; using GetTaskResultFunc = Func; using MethodExecutor = Func; using static Expression; @@ -63,11 +63,6 @@ async ValueTask OnRequestReceived(Request request) return; } var method = GetMethod(endpoint.Contract, request.MethodName); - if (request.HasObjectParameters && !method.ReturnType.IsGenericType) - { - await HandleRequest(method, endpoint, request, default); - return; - } Response response = null; var requestCancellation = Rent(); _requests[request.Id] = requestCancellation; @@ -111,7 +106,6 @@ ValueTask OnError(Request request, Exception ex) #endif async ValueTask HandleRequest(Method method, EndpointSettings endpoint, Request request, CancellationToken cancellationToken) { - var objectParameters = request.HasObjectParameters; var contract = endpoint.Contract; var arguments = GetArguments(); var beforeCall = endpoint.BeforeCall; @@ -152,12 +146,12 @@ async ValueTask InvokeMethod() { return Response.Success(request, downloadStream); } - return objectParameters ? new Response(request.Id, ObjectData: returnValue) : Response.Success(request, Serializer.Serialize(returnValue)); + return Response.Success(request, Serializer.Serialize(returnValue)); } else { (defaultScheduler ? MethodCall() : RunOnScheduler().Unwrap()).LogException(Logger, method.MethodInfo); - return objectParameters ? null : Response.Success(request, ""); + return Response.Success(request, ""); } Task MethodCall() => method.Invoke(service, arguments, cancellationToken); Task RunOnScheduler() => Task.Factory.StartNew(MethodCall, cancellationToken, TaskCreationOptions.DenyChildAttach, scheduler); @@ -166,12 +160,12 @@ object[] GetArguments() { var parameters = method.Parameters; var allParametersLength = parameters.Length; - var requestParametersLength = objectParameters ? request.ObjectParameters.Length : request.Parameters.Length; + var requestParametersLength = request.Parameters.Length; if (requestParametersLength > allParametersLength) { throw new ArgumentException("Too many parameters for " + method.MethodInfo); } - var allArguments = objectParameters && requestParametersLength == allParametersLength ? request.ObjectParameters : new object[allParametersLength]; + var allArguments = new object[allParametersLength]; Deserialize(); SetOptionalArguments(); return allArguments; @@ -191,9 +185,7 @@ void Deserialize() } else { - argument = objectParameters ? - Serializer.Deserialize(request.ObjectParameters[index], parameterType) : - Serializer.Deserialize(request.Parameters[index], parameterType); + argument = Serializer.Deserialize(request.Parameters[index], parameterType); argument = CheckMessage(argument, parameterType); } allArguments[index] = argument; @@ -209,7 +201,6 @@ object CheckMessage(object argument, Type parameterType) { message.CallbackContract = endpoint.CallbackContract; message.Client = _client; - message.ObjectParameters = objectParameters; } return argument; } diff --git a/src/UiPath.CoreIpc/Server/ServerConnection.cs b/src/UiPath.CoreIpc/Server/ServerConnection.cs index 43f11a6a..07442cd1 100644 --- a/src/UiPath.CoreIpc/Server/ServerConnection.cs +++ b/src/UiPath.CoreIpc/Server/ServerConnection.cs @@ -1,9 +1,9 @@ using System.Net.Security; -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; public interface IClient { - TCallbackInterface GetCallback(Type callbackContract, bool objectParameters) where TCallbackInterface : class; + TCallbackInterface GetCallback(Type callbackContract) where TCallbackInterface : class; void Impersonate(Action action); } abstract class ServerConnection : IClient, IDisposable @@ -18,7 +18,7 @@ abstract class ServerConnection : IClient, IDisposable public ListenerSettings Settings => _listener.Settings; public abstract Task AcceptClient(CancellationToken cancellationToken); public virtual void Impersonate(Action action) => action(); - TCallbackInterface IClient.GetCallback(Type callbackContract, bool objectParameters) where TCallbackInterface : class + TCallbackInterface IClient.GetCallback(Type callbackContract) where TCallbackInterface : class { if (callbackContract == null) { @@ -36,10 +36,7 @@ TCallbackInterface CreateCallback(Type callbackContract) _listener.Log($"Create callback {callbackContract} {_listener.Name}"); } _connectionAsTask ??= Task.FromResult(_connection); - var serviceClient = new ServiceClient(_connection.Serializer, Settings.RequestTimeout, Logger, (_, _) => _connectionAsTask) - { - ObjectParameters = objectParameters - }; + var serviceClient = new ServiceClient(_connection.Serializer, Settings.RequestTimeout, Logger, (_, _) => _connectionAsTask); return serviceClient.CreateProxy(); } } diff --git a/src/UiPath.CoreIpc/Server/ServiceHost.cs b/src/UiPath.CoreIpc/Server/ServiceHost.cs index 13a834b1..e008ff62 100644 --- a/src/UiPath.CoreIpc/Server/ServiceHost.cs +++ b/src/UiPath.CoreIpc/Server/ServiceHost.cs @@ -1,4 +1,4 @@ -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; public sealed class ServiceHost : IDisposable { private readonly CancellationTokenSource _cancellationTokenSource = new(); diff --git a/src/UiPath.CoreIpc/Server/ServiceHostBuilder.cs b/src/UiPath.CoreIpc/Server/ServiceHostBuilder.cs index e5c3474f..964f1bea 100644 --- a/src/UiPath.CoreIpc/Server/ServiceHostBuilder.cs +++ b/src/UiPath.CoreIpc/Server/ServiceHostBuilder.cs @@ -1,4 +1,4 @@ -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; using BeforeCallHandler = Func; public class ServiceHostBuilder diff --git a/src/UiPath.CoreIpc/TaskCompletionPool.cs b/src/UiPath.CoreIpc/TaskCompletionPool.cs index 11f9ece9..f1f971a2 100644 --- a/src/UiPath.CoreIpc/TaskCompletionPool.cs +++ b/src/UiPath.CoreIpc/TaskCompletionPool.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks.Sources; -namespace UiPath.CoreIpc; +namespace UiPath.Ipc; internal static class TaskCompletionPool { public static ManualResetValueTaskSource Rent() => ObjectPool.Rent(); diff --git a/src/UiPath.CoreIpc/Tcp/TcpClient.cs b/src/UiPath.CoreIpc/Tcp/TcpClient.cs index 50386575..fc6db29a 100644 --- a/src/UiPath.CoreIpc/Tcp/TcpClient.cs +++ b/src/UiPath.CoreIpc/Tcp/TcpClient.cs @@ -1,7 +1,7 @@ using System.Net; using System.Net.Sockets; -namespace UiPath.CoreIpc.Tcp; +namespace UiPath.Ipc.Tcp; using ConnectionFactory = Func>; using BeforeCallHandler = Func; @@ -11,10 +11,10 @@ interface ITcpKey : IConnectionKey } class TcpClient : ServiceClient, ITcpKey where TInterface : class { - public TcpClient(IPEndPoint endPoint, ISerializer serializer, TimeSpan requestTimeout, ILogger logger, ConnectionFactory connectionFactory, string sslServer, BeforeCallHandler beforeCall, bool objectParameters, EndpointSettings serviceEndpoint) : base(serializer, requestTimeout, logger, connectionFactory, sslServer, beforeCall, objectParameters, serviceEndpoint) + public TcpClient(IPEndPoint endPoint, ISerializer serializer, TimeSpan requestTimeout, ILogger logger, ConnectionFactory connectionFactory, BeforeCallHandler beforeCall, EndpointSettings serviceEndpoint) : base(serializer, requestTimeout, logger, connectionFactory, beforeCall, serviceEndpoint) { EndPoint = endPoint; - HashCode = (EndPoint, sslServer).GetHashCode(); + HashCode = EndPoint.GetHashCode(); } public override string Name => base.Name ?? EndPoint.ToString(); public IPEndPoint EndPoint { get; } diff --git a/src/UiPath.CoreIpc/Tcp/TcpClientBuilder.cs b/src/UiPath.CoreIpc/Tcp/TcpClientBuilder.cs index a0a05b71..7d8847f7 100644 --- a/src/UiPath.CoreIpc/Tcp/TcpClientBuilder.cs +++ b/src/UiPath.CoreIpc/Tcp/TcpClientBuilder.cs @@ -1,6 +1,6 @@ using System.Net; -namespace UiPath.CoreIpc.Tcp; +namespace UiPath.Ipc.Tcp; public abstract class TcpClientBuilderBase : ServiceClientBuilder where TInterface : class where TDerived : ServiceClientBuilder { @@ -10,7 +10,7 @@ protected TcpClientBuilderBase(IPEndPoint endPoint, Type callbackContract = null _endPoint = endPoint; protected override TInterface BuildCore(EndpointSettings serviceEndpoint) => - new TcpClient(_endPoint, _serializer, _requestTimeout, _logger, _connectionFactory, _sslServer, _beforeCall, _objectParameters, serviceEndpoint).CreateProxy(); + new TcpClient(_endPoint, _serializer, _requestTimeout, _logger, _connectionFactory, _beforeCall, serviceEndpoint).CreateProxy(); } public class TcpClientBuilder : TcpClientBuilderBase, TInterface> where TInterface : class diff --git a/src/UiPath.CoreIpc/Tcp/TcpListener.cs b/src/UiPath.CoreIpc/Tcp/TcpListener.cs index b2019e3c..73773f6f 100644 --- a/src/UiPath.CoreIpc/Tcp/TcpListener.cs +++ b/src/UiPath.CoreIpc/Tcp/TcpListener.cs @@ -1,5 +1,5 @@ using System.Net; -namespace UiPath.CoreIpc.Tcp; +namespace UiPath.Ipc.Tcp; public class TcpSettings : ListenerSettings { diff --git a/src/UiPath.CoreIpc/UiPath.CoreIpc.csproj b/src/UiPath.CoreIpc/UiPath.CoreIpc.csproj index b0111764..8f5732ed 100644 --- a/src/UiPath.CoreIpc/UiPath.CoreIpc.csproj +++ b/src/UiPath.CoreIpc/UiPath.CoreIpc.csproj @@ -1,7 +1,8 @@  net6.0;net461;net6.0-windows - UiPath.CoreIpc + UiPath.Ipc + UiPath.Ipc true UiPath 2.5.1 @@ -16,6 +17,7 @@ CA1416 latest true + annotations @@ -25,14 +27,19 @@ <_Parameter1>UiPath.CoreIpc.Tests - + - - + + + + + + + diff --git a/src/UiPath.CoreIpc/WebSockets/WebSocketClient.cs b/src/UiPath.CoreIpc/WebSockets/WebSocketClient.cs index f0774988..08f8620c 100644 --- a/src/UiPath.CoreIpc/WebSockets/WebSocketClient.cs +++ b/src/UiPath.CoreIpc/WebSockets/WebSocketClient.cs @@ -1,5 +1,5 @@ using System.Net.WebSockets; -namespace UiPath.CoreIpc.WebSockets; +namespace UiPath.Ipc.WebSockets; using ConnectionFactory = Func>; using BeforeCallHandler = Func; interface IWebSocketsKey : IConnectionKey @@ -8,10 +8,10 @@ interface IWebSocketsKey : IConnectionKey } class WebSocketClient : ServiceClient, IWebSocketsKey where TInterface : class { - public WebSocketClient(Uri uri, ISerializer serializer, TimeSpan requestTimeout, ILogger logger, ConnectionFactory connectionFactory, string sslServer, BeforeCallHandler beforeCall, bool objectParameters, EndpointSettings serviceEndpoint) : base(serializer, requestTimeout, logger, connectionFactory, sslServer, beforeCall, objectParameters, serviceEndpoint) + public WebSocketClient(Uri uri, ISerializer serializer, TimeSpan requestTimeout, ILogger logger, ConnectionFactory connectionFactory, BeforeCallHandler beforeCall, EndpointSettings serviceEndpoint) : base(serializer, requestTimeout, logger, connectionFactory, beforeCall, serviceEndpoint) { Uri = uri; - HashCode = (uri, sslServer).GetHashCode(); + HashCode = uri.GetHashCode(); } public override string Name => base.Name ?? Uri.ToString(); public Uri Uri { get; } diff --git a/src/UiPath.CoreIpc/WebSockets/WebSocketClientBuilder.cs b/src/UiPath.CoreIpc/WebSockets/WebSocketClientBuilder.cs index 893a8b7a..5c10fb41 100644 --- a/src/UiPath.CoreIpc/WebSockets/WebSocketClientBuilder.cs +++ b/src/UiPath.CoreIpc/WebSockets/WebSocketClientBuilder.cs @@ -1,11 +1,11 @@ -namespace UiPath.CoreIpc.WebSockets; +namespace UiPath.Ipc.WebSockets; public abstract class WebSocketClientBuilderBase : ServiceClientBuilder where TInterface : class where TDerived : ServiceClientBuilder { private readonly Uri _uri; protected WebSocketClientBuilderBase(Uri uri, Type callbackContract = null, IServiceProvider serviceProvider = null) : base(callbackContract, serviceProvider) => _uri = uri; protected override TInterface BuildCore(EndpointSettings serviceEndpoint) => - new WebSocketClient(_uri, _serializer, _requestTimeout, _logger, _connectionFactory, _sslServer, _beforeCall, _objectParameters, serviceEndpoint).CreateProxy(); + new WebSocketClient(_uri, _serializer, _requestTimeout, _logger, _connectionFactory, _beforeCall, serviceEndpoint).CreateProxy(); } public class WebSocketClientBuilder : WebSocketClientBuilderBase, TInterface> where TInterface : class { diff --git a/src/UiPath.CoreIpc/WebSockets/WebSocketListener.cs b/src/UiPath.CoreIpc/WebSockets/WebSocketListener.cs index 20b95a06..86d2be27 100644 --- a/src/UiPath.CoreIpc/WebSockets/WebSocketListener.cs +++ b/src/UiPath.CoreIpc/WebSockets/WebSocketListener.cs @@ -1,5 +1,5 @@ using System.Net.WebSockets; -namespace UiPath.CoreIpc.WebSockets; +namespace UiPath.Ipc.WebSockets; using Accept = Func>; public class WebSocketSettings : ListenerSettings { diff --git a/src/UiPath.CoreIpc/WebSockets/WebSocketStream.cs b/src/UiPath.CoreIpc/WebSockets/WebSocketStream.cs index c64b4816..7a5c814f 100644 --- a/src/UiPath.CoreIpc/WebSockets/WebSocketStream.cs +++ b/src/UiPath.CoreIpc/WebSockets/WebSocketStream.cs @@ -1,5 +1,5 @@ using System.Net.WebSockets; -namespace UiPath.CoreIpc.WebSockets; +namespace UiPath.Ipc.WebSockets; /// /// Exposes a as a . /// https://github.com/AArnott/Nerdbank.Streams/blob/main/src/Nerdbank.Streams/WebSocketStream.cs