├── .editorconfig ├── .gitattributes ├── .gitignore ├── DotNetTest.bat ├── LICENSE ├── README.md ├── UiPath.Rpc ├── CI │ ├── azp-dotnet-dist.yaml │ ├── azp-dotnet.yaml │ ├── azp-initialization.yaml │ └── azp-start.yaml ├── NuGet.Config ├── RpcSample.ConsoleClient │ ├── App1.config │ ├── Client.cs │ ├── RpcSample.ConsoleClient.csproj │ ├── TcpClient.cs │ ├── WebSocketClient.cs │ └── app1.manifest ├── RpcSample.ConsoleServer │ ├── App1.config │ ├── RpcSample.ConsoleServer.csproj │ ├── Server.cs │ ├── TcpServer.cs │ ├── WebSocketServer.cs │ └── app1.manifest ├── UiPath.Rpc.Tests │ ├── ComputingTests.cs │ ├── EndpointTests.cs │ ├── Implementation │ │ ├── ComputingCallback.cs │ │ ├── ComputingService.cs │ │ ├── IpcHelpers.cs │ │ ├── OneWayStreamWrapper.cs │ │ └── SystemService.cs │ ├── NamedPipeTests.cs │ ├── NestedStreamTests.cs │ ├── SystemTests.cs │ ├── TcpTests..cs │ ├── TestBase.cs │ ├── UiPath.Rpc.Tests.csproj │ ├── ValidationTests.cs │ └── WebSocketTests.cs ├── UiPath.Rpc.sln └── UiPath.Rpc │ ├── CancellationTokenSourcePool.cs │ ├── Client │ ├── ClientConnectionsRegistry.cs │ ├── ServiceClient.cs │ └── ServiceClientBuilder.cs │ ├── Connection.cs │ ├── Dtos.cs │ ├── GlobalSuppressions.cs │ ├── Helpers.cs │ ├── NamedPipe │ ├── NamedPipeClient.cs │ ├── NamedPipeClientBuilder.cs │ └── NamedPipeListener.cs │ ├── NestedStream.cs │ ├── Server │ ├── Listener.cs │ ├── Server.cs │ ├── ServerConnection.cs │ ├── ServiceHost.cs │ └── ServiceHostBuilder.cs │ ├── TaskCompletionPool.cs │ ├── Tcp │ ├── TcpClient.cs │ ├── TcpClientBuilder.cs │ └── TcpListener.cs │ ├── UiPath.Rpc.csproj │ └── WebSockets │ ├── WebSocketClient.cs │ ├── WebSocketClientBuilder.cs │ ├── WebSocketListener.cs │ └── WebSocketStream.cs └── src ├── CI ├── azp-dotnet-dist.yaml ├── azp-dotnet.yaml ├── azp-initialization.yaml ├── azp-js.publish-npm.steps.yaml ├── azp-nodejs-dist.yaml ├── azp-nodejs.yaml └── azp-start.yaml ├── Clients └── js │ ├── .editorconfig │ ├── .gitignore │ ├── .nycrc │ ├── .prettierrc.json │ ├── .vscode │ └── settings.json │ ├── README.md │ ├── assets │ ├── js-16x16.png │ ├── js-24x24.png │ ├── js-32x32.png │ ├── js-48x48.png │ ├── node │ │ ├── README.md │ │ └── npm-32x32.png │ ├── npm-16x16.png │ ├── npm-32x32.png │ ├── npm.png │ ├── npm.svg │ ├── web-js │ │ ├── README.md │ │ └── js-32x32.png │ └── web │ │ ├── README.md │ │ └── npm-32x32.png │ ├── dist-packages │ └── .gitkeep │ ├── dotnet │ ├── UiPath.CoreIpc.NodeInterop.sln │ └── UiPath.CoreIpc.NodeInterop │ │ ├── CompilerServices.cs │ │ ├── Contracts.cs │ │ ├── Program.cs │ │ ├── Properties │ │ └── launchSettings.json │ │ ├── ServiceImpls.cs │ │ ├── Signalling.cs │ │ └── UiPath.CoreIpc.NodeInterop.csproj │ ├── jasmine-console-reporter.d.ts │ ├── jasmine.node.json │ ├── jasmine.node.ts │ ├── karma.conf.js │ ├── package-lock.json │ ├── package.json │ ├── readme-assets │ ├── diagram.png │ ├── dotnet.png │ ├── nodejs.png │ ├── npm.png │ └── nuget.png │ ├── republish.bat │ ├── src │ ├── node │ │ ├── Ipc.ts │ │ ├── NodeAddressBuilder.ts │ │ ├── Platform.ts │ │ ├── Transport │ │ │ ├── NamedPipes │ │ │ │ ├── NamedPipeAddress.ts │ │ │ │ ├── NamedPipeSocket.ts │ │ │ │ ├── NamedPipeSocketLike.ts │ │ │ │ ├── NamedPipeSocketLikeCtor.ts │ │ │ │ └── index.ts │ │ │ ├── WebSockets │ │ │ │ ├── NodeWebSocket.ts │ │ │ │ ├── NodeWebSocketAddress.ts │ │ │ │ ├── NodeWebSocketError.ts │ │ │ │ ├── NodeWebSocketLike.ts │ │ │ │ ├── NodeWebSocketLikeCtor.ts │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ └── index.ts │ ├── std │ │ ├── bcl │ │ │ ├── cancellation │ │ │ │ ├── CancellationToken.ts │ │ │ │ ├── CancellationTokenRegistration.ts │ │ │ │ ├── CancellationTokenSource.ts │ │ │ │ ├── EmptyCancellationToken.ts │ │ │ │ ├── LinkedCancellationTokenSource.ts │ │ │ │ ├── RandomCancellationToken.ts │ │ │ │ └── index.ts │ │ │ ├── collections │ │ │ │ ├── ConditionalWeakTable.ts │ │ │ │ ├── Dictionary.ts │ │ │ │ └── index.ts │ │ │ ├── diagnostics │ │ │ │ ├── Trace.ts │ │ │ │ └── index.ts │ │ │ ├── disposable │ │ │ │ ├── AggregateDisposable.ts │ │ │ │ ├── IAsyncDisposable.ts │ │ │ │ ├── IDisposable.ts │ │ │ │ └── index.ts │ │ │ ├── errors │ │ │ │ ├── AggregateError.ts │ │ │ │ ├── ArgumentError.ts │ │ │ │ ├── ArgumentErrorBase.ts │ │ │ │ ├── ArgumentNullError.ts │ │ │ │ ├── ArgumentOutOfRangeError.ts │ │ │ │ ├── CoreIpcError.ts │ │ │ │ ├── EndOfStreamError.ts │ │ │ │ ├── InvalidOperationError.ts │ │ │ │ ├── ObjectDisposedError.ts │ │ │ │ ├── OperationCanceledError.ts │ │ │ │ ├── PlatformNotSupportedError.ts │ │ │ │ ├── TimeoutError.ts │ │ │ │ ├── UnknownError.ts │ │ │ │ └── index.ts │ │ │ ├── helpers │ │ │ │ ├── argumentIs.ts │ │ │ │ ├── index.ts │ │ │ │ └── nameof.ts │ │ │ ├── index.ts │ │ │ ├── io │ │ │ │ ├── BitConverter.ts │ │ │ │ ├── Marshal.ts │ │ │ │ ├── Socket.ts │ │ │ │ ├── SocketStream.ts │ │ │ │ ├── Stream.ts │ │ │ │ ├── SupportedConversion.ts │ │ │ │ └── index.ts │ │ │ ├── promises │ │ │ │ ├── FinalState.ts │ │ │ │ ├── PromiseCompletionSource.ts │ │ │ │ ├── PromiseCompletionSourceInternal.ts │ │ │ │ ├── PromisePal.ts │ │ │ │ ├── PromiseSpy.ts │ │ │ │ ├── PromiseSpyImpl.ts │ │ │ │ ├── PromiseStatus.ts │ │ │ │ └── index.ts │ │ │ ├── reflection │ │ │ │ ├── Constructor │ │ │ │ │ ├── ParameterlessPublic.ts │ │ │ │ │ ├── PublicCtor.ts │ │ │ │ │ ├── UnnamedPublicCtor.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── ObjectPal.ts │ │ │ │ ├── Type │ │ │ │ │ ├── ExtendedType.ts │ │ │ │ │ ├── Primitive.ts │ │ │ │ │ ├── PrimitiveDefinedNonObjectTypeName.ts │ │ │ │ │ ├── PrimitiveDefinedTypeName.ts │ │ │ │ │ ├── PrimitiveTypeName.ts │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── serialization │ │ │ │ ├── JsonConvert.ts │ │ │ │ └── index.ts │ │ │ ├── synchronization │ │ │ │ ├── AsyncAutoResetEvent.ts │ │ │ │ └── index.ts │ │ │ ├── system │ │ │ │ ├── IPlatform.ts │ │ │ │ └── index.ts │ │ │ └── time │ │ │ │ ├── TimeSpan.ts │ │ │ │ ├── Timeout.ts │ │ │ │ └── index.ts │ │ ├── core │ │ │ ├── Addresses │ │ │ │ ├── Address.ts │ │ │ │ ├── AddressBuilder.ts │ │ │ │ ├── AddressSelectionDelegate.ts │ │ │ │ └── index.ts │ │ │ ├── Annotations │ │ │ │ ├── OperationAnnotations.ts │ │ │ │ ├── OperationAnnotationsWrapper.ts │ │ │ │ ├── ServiceAnnotations.ts │ │ │ │ ├── ServiceAnnotationsWrapper.ts │ │ │ │ └── index.ts │ │ │ ├── Callbacks │ │ │ │ ├── Callback.ts │ │ │ │ ├── CallbackImpl.ts │ │ │ │ └── index.ts │ │ │ ├── Configuration │ │ │ │ ├── ConfigStore.ts │ │ │ │ ├── ConnectContext.ts │ │ │ │ ├── ConnectHelper.ts │ │ │ │ └── index.ts │ │ │ ├── Contract │ │ │ │ ├── ContractStore.ts │ │ │ │ ├── IContractStore.ts │ │ │ │ ├── Message.ts │ │ │ │ ├── OperationDescriptor.ts │ │ │ │ ├── OperationDescriptorImpl.ts │ │ │ │ ├── OperationDescriptorTable.ts │ │ │ │ ├── ServiceDescriptor.ts │ │ │ │ ├── ServiceDescriptorImpl.ts │ │ │ │ └── index.ts │ │ │ ├── IServiceProvider.ts │ │ │ ├── IpcBase.ts │ │ │ ├── Protocol │ │ │ │ ├── Errors │ │ │ │ │ ├── IpcError.ts │ │ │ │ │ ├── RemoteError.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── Network │ │ │ │ │ ├── IMessageStream.ts │ │ │ │ │ ├── MessageStream.ts │ │ │ │ │ ├── Network.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── Rpc │ │ │ │ │ ├── Converter.ts │ │ │ │ │ ├── IRpcChannel.ts │ │ │ │ │ ├── IRpcChannelFactory.ts │ │ │ │ │ ├── IncommingInitiatingRpcMessage.ts │ │ │ │ │ ├── RpcCallContext.ts │ │ │ │ │ ├── RpcChannel.ts │ │ │ │ │ ├── RpcMessage.ts │ │ │ │ │ ├── RpcMessageBase.ts │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── Proxies │ │ │ │ ├── CallbackStoreImpl.ts │ │ │ │ ├── ChannelManager.ts │ │ │ │ ├── DispatchProxy │ │ │ │ │ ├── DispatchProxyClass.ts │ │ │ │ │ ├── DispatchProxyClassStore.ts │ │ │ │ │ ├── ICallInterceptor.ts │ │ │ │ │ ├── ICallInterceptorContainer.ts │ │ │ │ │ ├── MethodNameEnumerator.ts │ │ │ │ │ ├── Weaver.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── ProxyId.ts │ │ │ │ ├── ProxySource.ts │ │ │ │ ├── RpcRequestFactory.ts │ │ │ │ ├── Wire.ts │ │ │ │ └── index.ts │ │ │ ├── ServiceId.ts │ │ │ └── index.ts │ │ └── index.ts │ └── web │ │ ├── Ipc.ts │ │ ├── Platform.ts │ │ ├── Transport │ │ ├── WebSockets │ │ │ ├── BrowserWebSocket.ts │ │ │ ├── BrowserWebSocketAddress.ts │ │ │ ├── BrowserWebSocketError.ts │ │ │ ├── BrowserWebSocketLike.ts │ │ │ ├── BrowserWebSocketLikeCtor.ts │ │ │ └── index.ts │ │ └── index.ts │ │ ├── WebAddressBuilder.ts │ │ └── index.ts │ ├── test │ ├── dotnet │ │ ├── CoreIpcServer │ │ │ ├── CoreIpcServer.ts │ │ │ ├── DotNetProcess.ts │ │ │ ├── InteropAddress.ts │ │ │ ├── NonZeroExitError.ts │ │ │ ├── NpmProcess.ts │ │ │ ├── Paths.ts │ │ │ ├── Signal.ts │ │ │ └── index.ts │ │ └── index.ts │ ├── infrastructure │ │ ├── MockServiceProvider.ts │ │ ├── __.ts │ │ ├── __members.ts │ │ ├── __parameters.ts │ │ ├── cover │ │ │ ├── index.ts │ │ │ └── internal │ │ │ │ ├── CoverTypeContext.ts │ │ │ │ ├── coverType.ts │ │ │ │ ├── funky.ts │ │ │ │ └── index.ts │ │ ├── cover2 │ │ │ ├── Cover.ts │ │ │ ├── funky.ts │ │ │ └── index.ts │ │ ├── coverOld.ts │ │ ├── index.ts │ │ └── overloadedParameters.ts │ ├── node │ │ ├── Contracts │ │ │ ├── IAlgebra.ts │ │ │ ├── IArithmetic.ts │ │ │ └── index.ts │ │ ├── Fixtures │ │ │ └── index.ts │ │ ├── core │ │ │ ├── ConfigStore.test.ts │ │ │ └── Ipc.test.ts │ │ └── end-to-end.test.ts │ ├── std │ │ └── bcl │ │ │ ├── AggregateDisposable.test.ts │ │ │ ├── AggregateError.test.ts │ │ │ ├── ArgumentError.test.ts │ │ │ ├── ArgumentNullError.test.ts │ │ │ ├── ArgumentOutOfRangeError.test.ts │ │ │ ├── AsyncAutoResetEvent.test.ts │ │ │ ├── CancellationToken.test.ts │ │ │ ├── CancellationTokenSource.test.ts │ │ │ ├── ConditionalWeakTable.test.ts │ │ │ ├── DispatchProxyClassStore.test.ts │ │ │ ├── PromiseCompletionSource.test.ts │ │ │ ├── PromisePal.test.ts │ │ │ ├── RandomCancellationToken.test.ts │ │ │ ├── TimeSpan.test.ts │ │ │ ├── Trace.test.ts │ │ │ └── final-states.spec.ts │ └── web │ │ ├── Contracts │ │ ├── IAlgebra.ts │ │ ├── IArithmetic.ts │ │ └── index.ts │ │ ├── Fixtures │ │ ├── AlgebraProxy.ts │ │ ├── ProxyFactory.ts │ │ ├── ServerUrl.ts │ │ └── index.ts │ │ ├── core │ │ └── ConfigStore.test.ts │ │ └── end-to-end.test.ts │ ├── tsconfig.common.json │ ├── tsconfig.dotnet.json │ ├── tsconfig.jasmine.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── tsconfig.test.json │ ├── tsconfig.web-js.json │ ├── tsconfig.web.json │ ├── tslint.json │ ├── webpack.common.js │ └── webpack.dev.js ├── CoreIpc.sln ├── IpcSample.ConsoleClient ├── App1.config ├── Client.cs ├── IpcSample.ConsoleClient.csproj ├── TcpClient.cs ├── WebSocketClient.cs └── app1.manifest ├── IpcSample.ConsoleServer ├── App1.config ├── IpcSample.ConsoleServer.csproj ├── Server.cs ├── TcpServer.cs ├── WebSocketServer.cs └── app1.manifest ├── NuGet.Config ├── UiPath.CoreIpc.Tests ├── ComputingTests.cs ├── EndpointTests.cs ├── Implementation │ ├── ComputingCallback.cs │ ├── ComputingService.cs │ ├── IpcHelpers.cs │ ├── OneWayStreamWrapper.cs │ └── SystemService.cs ├── NamedPipeTests.cs ├── NestedStreamTests.cs ├── SystemTests.cs ├── TcpTests..cs ├── TestBase.cs ├── UiPath.CoreIpc.Tests.csproj ├── ValidationTests.cs └── WebSocketTests.cs └── UiPath.CoreIpc ├── CancellationTokenSourcePool.cs ├── Client ├── ClientConnectionsRegistry.cs ├── ServiceClient.cs └── ServiceClientBuilder.cs ├── Connection.cs ├── Dtos.cs ├── GlobalSuppressions.cs ├── Helpers.cs ├── IpcJsonSerializer.cs ├── NamedPipe ├── NamedPipeClient.cs ├── NamedPipeClientBuilder.cs └── NamedPipeListener.cs ├── NestedStream.cs ├── Server ├── Listener.cs ├── Server.cs ├── ServerConnection.cs ├── ServiceHost.cs └── ServiceHostBuilder.cs ├── TaskCompletionPool.cs ├── Tcp ├── TcpClient.cs ├── TcpClientBuilder.cs └── TcpListener.cs ├── UiPath.CoreIpc.csproj └── WebSockets ├── WebSocketClient.cs ├── WebSocketClientBuilder.cs ├── WebSocketListener.cs └── WebSocketStream.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | *.doc diff=astextplain 2 | *.DOC diff=astextplain 3 | *.docx diff=astextplain 4 | *.DOCX diff=astextplain 5 | *.dot diff=astextplain 6 | *.DOT diff=astextplain 7 | *.pdf diff=astextplain 8 | *.PDF diff=astextplain 9 | *.rtf diff=astextplain 10 | *.RTF diff=astextplain 11 | 12 | *.jpg binary 13 | *.png binary 14 | *.gif binary 15 | 16 | core.eol crlf 17 | 18 | *.cs diff=csharp 19 | 20 | *.csproj merge=union 21 | *.vbproj merge=union 22 | *.fsproj merge=union 23 | *.dbproj merge=union 24 | *.sln merge=union 25 | *.* linguist-detectable=false 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | release/ 3 | scripts/ 4 | artifacts/ 5 | .dotnet 6 | TestResults/ 7 | *.diagsession 8 | *.suo 9 | *.user 10 | bin 11 | Bin 12 | obj 13 | _ReSharper* 14 | *.csproj.user 15 | *.resharper.user 16 | *.suo 17 | *.cache 18 | TestResult.xml 19 | AppPackages/ 20 | *.bak 21 | packages 22 | *.orig 23 | *.DotSettings 24 | *.ide/ 25 | .nuget 26 | project.lock.json 27 | .vs 28 | 29 | # JetBrains Rider 30 | .idea/ 31 | *.sln.iml 32 | 33 | # Read the Docs 34 | docs/_build 35 | /src/LastMajorVersionBinary 36 | 37 | # Mac Finder 38 | .DS_Store 39 | -------------------------------------------------------------------------------- /DotNetTest.bat: -------------------------------------------------------------------------------- 1 | CD C:\Projects\CoreIpc\ 2 | FOR /L %%G IN (0,1,10) DO ( 3 | echo RUN %%G 4 | dotnet test --no-build -c Debug 5 | ) 6 | PAUSE -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 UiPath 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /UiPath.Rpc/CI/azp-dotnet-dist.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - task: CopyFiles@2 3 | displayName: '$(Label_DotNet) Copy nupkg to $(Build.ArtifactStagingDirectory)' 4 | inputs: 5 | SourceFolder: 'UiPath.Rpc\UiPath.Rpc\bin\$(DotNet_BuildConfiguration)\' 6 | Contents: '*.*nupkg' 7 | TargetFolder: '$(Build.ArtifactStagingDirectory)' 8 | CleanTargetFolder: true 9 | 10 | - task: PublishBuildArtifacts@1 11 | displayName: '$(Label_DotNet) Publish the $(DotNet_ArtifactName) to the pipeline instance' 12 | inputs: 13 | ArtifactName: '$(DotNet_ArtifactName)' 14 | PathtoPublish: '$(Build.ArtifactStagingDirectory)' 15 | ArtifactType: 'Container' 16 | 17 | - task: DotNetCoreCLI@2 18 | displayName: 'dotnet push to UiPath-Internal' 19 | condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) 20 | inputs: 21 | command: push 22 | packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg' 23 | publishVstsFeed: 'Public.Feeds/UiPath-Internal' 24 | 25 | - task: PublishSymbols@2 26 | displayName: 'Publish Symbols to UiPath Azure Artifacts Symbol Server' 27 | condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) 28 | inputs: 29 | symbolsFolder: $(Build.SourcesDirectory) 30 | searchPattern: '**/UiPath.Rpc/bin/**/UiPath.Rpc.pdb' 31 | symbolServerType: teamServices 32 | indexSources: false -------------------------------------------------------------------------------- /UiPath.Rpc/CI/azp-dotnet.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - task: DotNetCoreCLI@2 3 | displayName: '$(Label_DotNet) Run unit tests' 4 | inputs: 5 | command: 'test' 6 | projects: '$(DotNet_SessionSolution)' 7 | publishTestResults: true 8 | testRunTitle: '.NET tests' 9 | arguments: ' --configuration $(DotNet_BuildConfiguration) --logger "console;verbosity=detailed" -p:Version="$(FullVersion)" -p:DefineConstantsEx="CI"' -------------------------------------------------------------------------------- /UiPath.Rpc/CI/azp-initialization.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | 3 | # Read $(Version) from the UiPath.Rpc.csproj file 4 | - powershell: | 5 | $xml = [Xml] ( Get-Content $env:DotNet_MainProjectPath ) 6 | $version = [String] $xml.Project.PropertyGroup.Version 7 | $version = $version.Trim() 8 | 9 | Write-Host "##vso[task.setvariable variable=Version;]$version" 10 | 11 | displayName: '$(Label_Initialization) Read $[Version] from the csproj' 12 | env: 13 | DotNet_MainProjectPath: $(DotNet_MainProjectPath) 14 | 15 | # If $(PublishRelease) != "true" then compute $(FullVersion) as $(Version)-$(Build.BuildNumber) 16 | - task: VariableTransformTask@1 17 | displayName: '$(Label_Initialization) Compute $[FullVersion] when $[PublishRelease] is not true' 18 | inputs: 19 | value: '$(Version)-$(Build.BuildNumber)' 20 | variableName: 'FullVersion' 21 | IsSecret: false 22 | transformAction: 'none' 23 | condition: ne(variables['PublishRelease'], 'true') 24 | 25 | # If $(PublishRelease) == "true" then compute $(FullVersion) as $(Version) 26 | - task: VariableTransformTask@1 27 | displayName: '$(Label_Initialization) Compute $[FullVersion] when $[PublishRelease] is "true"' 28 | inputs: 29 | value: '$(Version)' 30 | variableName: 'FullVersion' 31 | IsSecret: false 32 | transformAction: 'none' 33 | condition: eq(variables['PublishRelease'], 'true') 34 | -------------------------------------------------------------------------------- /UiPath.Rpc/CI/azp-start.yaml: -------------------------------------------------------------------------------- 1 | name: $(Date:yyyyMMdd)$(Rev:-rr) 2 | 3 | variables: 4 | Label_Initialization: 'Initialization:' 5 | Label_DotNet: '.NET:' 6 | Label_NodeJS: 'node.js:' 7 | 8 | DotNet_BuildConfiguration: 'Release' 9 | DotNet_SessionSolution: 'UiPath.Rpc/UiPath.Rpc.sln' 10 | DotNet_MainProjectName: 'UiPath.Rpc' 11 | DotNet_MainProjectPath: './UiPath.Rpc/UiPath.Rpc/UiPath.Rpc.csproj' 12 | DotNet_ArtifactName: 'NuGet package' 13 | 14 | NodeJS_DotNet_BuildConfiguration: 'Debug' 15 | NodeJS_ProjectPath: './src/Clients/nodejs' 16 | NodeJS_ArchivePath: './src/Clients/nodejs.zip' 17 | NodeJS_ArtifactName: 'NPM package' 18 | NodeJS_NetCoreAppTargetDir_RelativePath: 'dotnet/UiPath.Rpc.NodeInterop/bin/Debug/net6.0' 19 | NodeJS_DotNetNodeInteropProject : './src/Clients/nodejs/dotnet/UiPath.Rpc.NodeInterop/UiPath.Rpc.NodeInterop.csproj' 20 | NodeJS_DotNetNodeInteropSolution: './src/Clients/nodejs/dotnet/UiPath.Rpc.NodeInterop.sln' 21 | jobs: 22 | 23 | - job: 24 | displayName: '.NET on Windows' 25 | pool: 26 | vmImage: 'windows-latest' 27 | steps: 28 | - template: azp-initialization.yaml 29 | - template: azp-dotnet.yaml 30 | - template: azp-dotnet-dist.yaml 31 | -------------------------------------------------------------------------------- /UiPath.Rpc/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /UiPath.Rpc/RpcSample.ConsoleClient/App1.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /UiPath.Rpc/RpcSample.ConsoleClient/RpcSample.ConsoleClient.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net7.0-windows;net461;net7.0; 6 | app1.manifest 7 | latest 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /UiPath.Rpc/RpcSample.ConsoleServer/App1.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /UiPath.Rpc/RpcSample.ConsoleServer/RpcSample.ConsoleServer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net7.0-windows;net461;net7.0; 6 | app1.manifest 7 | latest 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /UiPath.Rpc/RpcSample.ConsoleServer/Server.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System.Diagnostics; 3 | using UiPath.Rpc.NamedPipe; 4 | 5 | namespace UiPath.Rpc.Tests; 6 | 7 | class Server 8 | { 9 | //private static readonly Timer _timer = new Timer(_ => 10 | //{ 11 | // Console.WriteLine("GC.Collect"); 12 | // GC.Collect(); 13 | // GC.WaitForPendingFinalizers(); 14 | // GC.Collect(); 15 | //}, null, 0, 3000); 16 | static async Task Main() 17 | { 18 | Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); 19 | //GuiLikeSyncContext.Install(); 20 | Console.WriteLine(SynchronizationContext.Current); 21 | var serviceProvider = ConfigureServices(); 22 | // build and run service host 23 | var host = new ServiceHostBuilder(serviceProvider) 24 | .UseNamedPipes(new NamedPipeSettings("test") 25 | { 26 | RequestTimeout = TimeSpan.FromSeconds(2), 27 | //AccessControl = security => security.AllowCurrentUser(), 28 | }) 29 | .AddEndpoint() 30 | .AddEndpoint() 31 | .ValidateAndBuild(); 32 | 33 | await await Task.WhenAny(host.RunAsync(), Task.Run(() => 34 | { 35 | Console.WriteLine(typeof(int).Assembly); 36 | Console.ReadLine(); 37 | host.Dispose(); 38 | })); 39 | 40 | Console.WriteLine("Server stopped."); 41 | } 42 | 43 | private static IServiceProvider ConfigureServices() => 44 | new ServiceCollection() 45 | .AddRpcWithLogging() 46 | .AddSingleton() 47 | .AddSingleton() 48 | .BuildServiceProvider(); 49 | } -------------------------------------------------------------------------------- /UiPath.Rpc/RpcSample.ConsoleServer/TcpServer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System.Diagnostics; 3 | using System.Net; 4 | using UiPath.Rpc.Tcp; 5 | 6 | namespace UiPath.Rpc.Tests; 7 | 8 | class TcpServer 9 | { 10 | static readonly IPEndPoint SystemEndPoint = new(IPAddress.Any, 3131); 11 | //private static readonly Timer _timer = new Timer(_ => 12 | //{ 13 | // Console.WriteLine("GC.Collect"); 14 | // GC.Collect(); 15 | // GC.WaitForPendingFinalizers(); 16 | // GC.Collect(); 17 | //}, null, 0, 3000); 18 | 19 | static async Task _Main() 20 | { 21 | Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); 22 | //GuiLikeSyncContext.Install(); 23 | Console.WriteLine(SynchronizationContext.Current); 24 | var serviceProvider = ConfigureServices(); 25 | // build and run service host 26 | var data = File.ReadAllBytes(@"../../../../localhost.pfx"); 27 | var host = new ServiceHostBuilder(serviceProvider) 28 | .UseTcp(new TcpSettings(SystemEndPoint) 29 | { 30 | RequestTimeout = TimeSpan.FromSeconds(2), 31 | //Certificate = new X509Certificate(data, "1"), 32 | }) 33 | .AddEndpoint() 34 | .AddEndpoint() 35 | .ValidateAndBuild(); 36 | 37 | await await Task.WhenAny(host.RunAsync(), Task.Run(() => 38 | { 39 | Console.WriteLine(typeof(int).Assembly); 40 | Console.ReadLine(); 41 | host.Dispose(); 42 | })); 43 | 44 | Console.WriteLine("Server stopped."); 45 | } 46 | 47 | private static IServiceProvider ConfigureServices() => 48 | new ServiceCollection() 49 | .AddRpcWithLogging() 50 | .AddSingleton() 51 | .AddSingleton() 52 | .BuildServiceProvider(); 53 | } -------------------------------------------------------------------------------- /UiPath.Rpc/RpcSample.ConsoleServer/WebSocketServer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System.Diagnostics; 3 | using System.Net; 4 | using System.Net.WebSockets; 5 | using UiPath.Rpc.WebSockets; 6 | namespace UiPath.Rpc.Tests; 7 | class WebSocketServer 8 | { 9 | //private static readonly Timer _timer = new Timer(_ => 10 | //{ 11 | // Console.WriteLine("GC.Collect"); 12 | // GC.Collect(); 13 | // GC.WaitForPendingFinalizers(); 14 | // GC.Collect(); 15 | //}, null, 0, 3000); 16 | 17 | static async Task _Main() 18 | { 19 | Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); 20 | //GuiLikeSyncContext.Install(); 21 | Console.WriteLine(SynchronizationContext.Current); 22 | var serviceProvider = ConfigureServices(); 23 | // build and run service host 24 | //var data = File.ReadAllBytes(@"../../../../localhost.pfx"); 25 | var host = new ServiceHostBuilder(serviceProvider) 26 | .UseWebSockets(new(new HttpSysWebSocketsListener("http://localhost:1212/wsDemo/").Accept) 27 | { 28 | RequestTimeout = TimeSpan.FromSeconds(2), 29 | //Certificate = new X509Certificate(data, "1"), 30 | }) 31 | .AddEndpoint() 32 | .AddEndpoint() 33 | .ValidateAndBuild(); 34 | await await Task.WhenAny(host.RunAsync(), Task.Run(() => 35 | { 36 | Console.WriteLine(typeof(int).Assembly); 37 | Console.ReadLine(); 38 | host.Dispose(); 39 | })); 40 | Console.WriteLine("Server stopped."); 41 | return; 42 | } 43 | private static IServiceProvider ConfigureServices() => 44 | new ServiceCollection() 45 | .AddRpcWithLogging() 46 | .AddSingleton() 47 | .AddSingleton() 48 | .BuildServiceProvider(); 49 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc.Tests/Implementation/ComputingCallback.cs: -------------------------------------------------------------------------------- 1 | namespace UiPath.Rpc.Tests; 2 | 3 | public interface IComputingCallback 4 | { 5 | Task GetId(Message message); 6 | Task GetThreadName(); 7 | } 8 | public class ComputingCallback : IComputingCallback 9 | { 10 | public string Id { get; set; } 11 | public async Task GetId(Message message) 12 | { 13 | message.Client.ShouldBeNull(); 14 | return Id; 15 | } 16 | 17 | public async Task GetThreadName() => Thread.CurrentThread.Name; 18 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc.Tests/TcpTests..cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using UiPath.Rpc.Tcp; 3 | namespace UiPath.Rpc.Tests; 4 | public class SystemTcpTests : SystemTests> 5 | { 6 | int _port = 3131 + GetCount(); 7 | protected override ServiceHostBuilder Configure(ServiceHostBuilder serviceHostBuilder) => 8 | serviceHostBuilder.UseTcp(Configure(new TcpSettings(GetEndPoint()))); 9 | protected override TcpClientBuilder CreateSystemClientBuilder() => new(GetEndPoint()); 10 | IPEndPoint GetEndPoint() => new(IPAddress.Loopback, _port); 11 | } 12 | public class ComputingTcpTests : ComputingTests> 13 | { 14 | protected readonly IPEndPoint ComputingEndPoint = new(IPAddress.Loopback, 2121+GetCount()); 15 | protected override TcpClientBuilder ComputingClientBuilder(TaskScheduler taskScheduler = null) => 16 | new TcpClientBuilder(ComputingEndPoint, _serviceProvider) 17 | .RequestTimeout(RequestTimeout) 18 | .CallbackInstance(_computingCallback) 19 | .TaskScheduler(taskScheduler); 20 | protected override ServiceHostBuilder Configure(ServiceHostBuilder serviceHostBuilder) => 21 | serviceHostBuilder.UseTcp(Configure(new TcpSettings(ComputingEndPoint))); 22 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc.Tests/TestBase.cs: -------------------------------------------------------------------------------- 1 | using Nito.AsyncEx; 2 | 3 | namespace UiPath.Rpc.Tests; 4 | 5 | public abstract class TestBase : IDisposable 6 | { 7 | protected const int MaxReceivedMessageSizeInMegabytes = 1; 8 | protected static int Count = -1; 9 | public static readonly TimeSpan RequestTimeout = 10 | #if CI 11 | TimeSpan.FromSeconds(3) + 12 | #endif 13 | (Debugger.IsAttached ? TimeSpan.FromDays(1) : TimeSpan.FromSeconds(2)); 14 | protected readonly IServiceProvider _serviceProvider; 15 | protected readonly AsyncContext _guiThread = new AsyncContextThread().Context; 16 | 17 | //static TestBase() 18 | //{ 19 | // AppContext.SetSwitch("Switch.System.Net.DontEnableSystemDefaultTlsVersions", false); 20 | //} 21 | public TestBase() 22 | { 23 | _guiThread.SynchronizationContext.Send(() => Thread.CurrentThread.Name = "GuiThread"); 24 | _serviceProvider = RpcHelpers.ConfigureServices(); 25 | } 26 | 27 | protected static int GetCount() => Interlocked.Increment(ref Count); 28 | 29 | protected TaskScheduler GuiScheduler => _guiThread.Scheduler; 30 | 31 | public virtual void Dispose() => _guiThread.Dispose(); 32 | protected virtual TSettings Configure(TSettings listenerSettings) where TSettings : ListenerSettings 33 | { 34 | listenerSettings.RequestTimeout = RequestTimeout; 35 | listenerSettings.MaxReceivedMessageSizeInMegabytes = MaxReceivedMessageSizeInMegabytes; 36 | return listenerSettings; 37 | } 38 | protected abstract ServiceHostBuilder Configure(ServiceHostBuilder serviceHostBuilder); 39 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc.Tests/UiPath.Rpc.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0;net461;net7.0-windows 5 | $(NoWarn);1998 6 | $(DefineConstants);$(DefineConstantsEx) 7 | latest 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc.Tests/WebSocketTests.cs: -------------------------------------------------------------------------------- 1 | using UiPath.Rpc.WebSockets; 2 | namespace UiPath.Rpc.Tests; 3 | public class SystemWebSocketTests : SystemTests> 4 | { 5 | int _port = 1313 + GetCount(); 6 | HttpSysWebSocketsListener _listener; 7 | protected override ServiceHostBuilder Configure(ServiceHostBuilder serviceHostBuilder) 8 | { 9 | _listener = new HttpSysWebSocketsListener("http" + GetEndPoint()); 10 | return serviceHostBuilder.UseWebSockets(Configure(new WebSocketSettings(_listener.Accept))); 11 | } 12 | public override void Dispose() 13 | { 14 | base.Dispose(); 15 | _listener?.Dispose(); 16 | } 17 | protected override WebSocketClientBuilder CreateSystemClientBuilder() => new(new("ws"+GetEndPoint())); 18 | [Fact(Skip = "WebSocket.State is unreliable")] 19 | public override Task UploadNoRead() => base.UploadNoRead(); 20 | string GetEndPoint() => $"://localhost:{_port}/"; 21 | } 22 | public class ComputingWebSocketsTests : ComputingTests> 23 | { 24 | protected static readonly string ComputingEndPoint = $"://localhost:{1212+GetCount()}/"; 25 | HttpSysWebSocketsListener _listener; 26 | protected override WebSocketClientBuilder ComputingClientBuilder(TaskScheduler taskScheduler = null) => 27 | new WebSocketClientBuilder(new("ws"+ComputingEndPoint), _serviceProvider) 28 | .RequestTimeout(RequestTimeout) 29 | .CallbackInstance(_computingCallback) 30 | .TaskScheduler(taskScheduler); 31 | protected override ServiceHostBuilder Configure(ServiceHostBuilder serviceHostBuilder) 32 | { 33 | _listener = new HttpSysWebSocketsListener("http" + ComputingEndPoint); 34 | return serviceHostBuilder.UseWebSockets(Configure(new WebSocketSettings(_listener.Accept))); 35 | } 36 | public override void Dispose() 37 | { 38 | base.Dispose(); 39 | _listener?.Dispose(); 40 | } 41 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc/CancellationTokenSourcePool.cs: -------------------------------------------------------------------------------- 1 | namespace UiPath.Rpc; 2 | // https://github.com/dotnet/aspnetcore/blob/main/src/Shared/CancellationTokenSourcePool.cs 3 | static class CancellationTokenSourcePool 4 | { 5 | public static PooledCancellationTokenSource Rent() => 6 | #if !NET461 7 | ObjectPool.TryRent() ?? new(); 8 | #else 9 | new(); 10 | #endif 11 | static bool Return(PooledCancellationTokenSource cts) => ObjectPool.Return(cts); 12 | public sealed class PooledCancellationTokenSource : CancellationTokenSource 13 | { 14 | public void Return() 15 | { 16 | // If we failed to return to the pool then dispose 17 | #if !NET461 18 | if (!TryReset() || !CancellationTokenSourcePool.Return(this)) 19 | #endif 20 | { 21 | Dispose(); 22 | } 23 | } 24 | } 25 | } 26 | static class ObjectPool 27 | { 28 | private const int MaxQueueSize = 1024; 29 | private static readonly ConcurrentQueue Cache = new(); 30 | private static int Count; 31 | public static T TryRent() 32 | { 33 | if (Cache.TryDequeue(out var pooled)) 34 | { 35 | Interlocked.Decrement(ref Count); 36 | return pooled; 37 | } 38 | return pooled; 39 | } 40 | public static bool Return(T item) 41 | { 42 | if (Interlocked.Increment(ref Count) > MaxQueueSize) 43 | { 44 | Interlocked.Decrement(ref Count); 45 | return false; 46 | } 47 | Cache.Enqueue(item); 48 | return true; 49 | } 50 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | using System.Diagnostics.CodeAnalysis; 6 | [assembly: SuppressMessage("Performance", "HAA0505:Initializer reference type allocation", Scope = "module")] 7 | [assembly: SuppressMessage("Performance", "HAA0502:Explicit new reference type allocation", Scope = "module")] 8 | [assembly: SuppressMessage("Performance", "HAA0501:Explicit new array type allocation", Scope = "module")] 9 | #if NET461 10 | namespace System.Runtime.CompilerServices; 11 | static class IsExternalInit 12 | { 13 | } 14 | #endif -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc/Server/ServiceHost.cs: -------------------------------------------------------------------------------- 1 | namespace UiPath.Rpc; 2 | public sealed class ServiceHost : IDisposable 3 | { 4 | private readonly CancellationTokenSource _cancellationTokenSource = new(); 5 | private readonly Listener[] _listeners; 6 | internal ServiceHost(IEnumerable listeners) => _listeners = listeners.ToArray(); 7 | public void Dispose() 8 | { 9 | if(_cancellationTokenSource.IsCancellationRequested) 10 | { 11 | return; 12 | } 13 | foreach (var listener in _listeners) 14 | { 15 | listener.Dispose(); 16 | } 17 | _cancellationTokenSource.Cancel(); 18 | _cancellationTokenSource.AssertDisposed(); 19 | } 20 | public Task RunAsync() => Task.WhenAll(Array.ConvertAll(_listeners, listener => listener.Listen(_cancellationTokenSource.Token))); 21 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc/TaskCompletionPool.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks.Sources; 2 | namespace UiPath.Rpc; 3 | static class TaskCompletionPool 4 | { 5 | public static ManualResetValueTaskSource Rent() => ObjectPool.TryRent() ?? new(); 6 | static void Return(ManualResetValueTaskSource source) => ObjectPool.Return(source); 7 | public sealed class ManualResetValueTaskSource : IValueTaskSource, IValueTaskSource, IErrorCompletion 8 | { 9 | private ManualResetValueTaskSourceCore _core; // mutable struct; do not make this readonly 10 | public bool RunContinuationsAsynchronously { get => _core.RunContinuationsAsynchronously; set => _core.RunContinuationsAsynchronously = value; } 11 | public short Version => _core.Version; 12 | public ValueTask ValueTask() => new(this, Version); 13 | public void Reset() => _core.Reset(); 14 | public void SetResult(T result) => _core.SetResult(result); 15 | public void SetException(Exception error) => _core.SetException(error); 16 | public void SetCanceled() => _core.SetException(new TaskCanceledException()); 17 | public T GetResult(short token) => _core.GetResult(token); 18 | void IValueTaskSource.GetResult(short token) => _core.GetResult(token); 19 | public ValueTaskSourceStatus GetStatus(short token) => _core.GetStatus(token); 20 | public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _core.OnCompleted(continuation, state, token, flags); 21 | public void Return() 22 | { 23 | Reset(); 24 | TaskCompletionPool.Return(this); 25 | } 26 | } 27 | } 28 | interface IErrorCompletion 29 | { 30 | void SetException(Exception error); 31 | void SetCanceled(); 32 | void Return(); 33 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc/Tcp/TcpClient.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Sockets; 3 | namespace UiPath.Rpc.Tcp; 4 | using ConnectionFactory = Func; 5 | using BeforeCallHandler = Func; 6 | interface ITcpKey : IConnectionKey 7 | { 8 | IPEndPoint EndPoint { get; } 9 | } 10 | class TcpClient : ServiceClient, ITcpKey where TInterface : class 11 | { 12 | public TcpClient(IPEndPoint endPoint, TimeSpan requestTimeout, ILogger logger, ConnectionFactory connectionFactory, BeforeCallHandler beforeCall, EndpointSettings serviceEndpoint) : base(requestTimeout, logger, connectionFactory, beforeCall, serviceEndpoint) 13 | { 14 | EndPoint = endPoint; 15 | HashCode = EndPoint.GetHashCode(); 16 | } 17 | public override string Name => base.Name ?? EndPoint.ToString(); 18 | public IPEndPoint EndPoint { get; } 19 | public override bool Equals(IConnectionKey other) => other == this || (other is ITcpKey otherClient && EndPoint.Equals(otherClient.EndPoint) && 20 | base.Equals(other)); 21 | public override ClientConnection CreateClientConnection() => new TcpClientConnection(this); 22 | class TcpClientConnection : ClientConnection 23 | { 24 | private TcpClient _tcpClient; 25 | public TcpClientConnection(IConnectionKey connectionKey) : base(connectionKey) {} 26 | public override bool Connected => _tcpClient?.Client?.Connected is true; 27 | protected override void Dispose(bool disposing) 28 | { 29 | _tcpClient?.Dispose(); 30 | base.Dispose(disposing); 31 | } 32 | public override async Task Connect(CancellationToken cancellationToken) 33 | { 34 | _tcpClient = new(); 35 | var endPoint = ((ITcpKey)ConnectionKey).EndPoint; 36 | await _tcpClient.ConnectAsync(endPoint.Address, endPoint.Port, cancellationToken).ConfigureAwait(false); 37 | return _tcpClient.GetStream(); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc/Tcp/TcpClientBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | namespace UiPath.Rpc.Tcp; 3 | public abstract class TcpClientBuilderBase : ServiceClientBuilder where TInterface : class where TDerived : ServiceClientBuilder 4 | { 5 | private readonly IPEndPoint _endPoint; 6 | protected TcpClientBuilderBase(IPEndPoint endPoint, Type callbackContract = null, IServiceProvider serviceProvider = null) : base(callbackContract, serviceProvider) => 7 | _endPoint = endPoint; 8 | protected override TInterface BuildCore(EndpointSettings serviceEndpoint) => 9 | new TcpClient(_endPoint, _requestTimeout, _logger, _connectionFactory, _beforeCall, serviceEndpoint).CreateProxy(); 10 | } 11 | public class TcpClientBuilder : TcpClientBuilderBase, TInterface> where TInterface : class 12 | { 13 | public TcpClientBuilder(IPEndPoint endPoint) : base(endPoint){} 14 | } 15 | public class TcpClientBuilder : TcpClientBuilderBase, TInterface> where TInterface : class where TCallbackInterface : class 16 | { 17 | public TcpClientBuilder(IPEndPoint endPoint, IServiceProvider serviceProvider) : base(endPoint, typeof(TCallbackInterface), serviceProvider) { } 18 | public TcpClientBuilder CallbackInstance(TCallbackInterface singleton) 19 | { 20 | _callbackInstance = singleton; 21 | return this; 22 | } 23 | public TcpClientBuilder TaskScheduler(TaskScheduler taskScheduler) 24 | { 25 | _taskScheduler = taskScheduler; 26 | return this; 27 | } 28 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc/Tcp/TcpListener.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | namespace UiPath.Rpc.Tcp; 3 | public class TcpSettings : ListenerSettings 4 | { 5 | public TcpSettings(IPEndPoint endPoint) : base(endPoint.ToString()) 6 | { 7 | EndPoint = endPoint; 8 | } 9 | public IPEndPoint EndPoint { get; } 10 | } 11 | class TcpListener : Listener 12 | { 13 | readonly System.Net.Sockets.TcpListener _tcpServer; 14 | public TcpListener(ListenerSettings settings) : base(settings) 15 | { 16 | _tcpServer = new(Settings.EndPoint); 17 | _tcpServer.Start(backlog: Settings.ConcurrentAccepts); 18 | } 19 | public new TcpSettings Settings => (TcpSettings)base.Settings; 20 | protected override ServerConnection CreateServerConnection() => new TcpServerConnection(this); 21 | protected override void Dispose(bool disposing) 22 | { 23 | base.Dispose(disposing); 24 | _tcpServer.Stop(); 25 | } 26 | Task AcceptClient(CancellationToken cancellationToken) => _tcpServer.AcceptTcpClientAsync(); 27 | class TcpServerConnection : ServerConnection 28 | { 29 | System.Net.Sockets.TcpClient _tcpClient; 30 | public TcpServerConnection(Listener listener) : base(listener){} 31 | public override async Task AcceptClient(CancellationToken cancellationToken) 32 | { 33 | _tcpClient = await ((TcpListener)_listener).AcceptClient(cancellationToken).ConfigureAwait(false); 34 | return _tcpClient.GetStream(); 35 | } 36 | protected override void Dispose(bool disposing) 37 | { 38 | _tcpClient?.Dispose(); 39 | base.Dispose(disposing); 40 | } 41 | } 42 | } 43 | public static class TcpServiceExtensions 44 | { 45 | public static ServiceHostBuilder UseTcp(this ServiceHostBuilder builder, TcpSettings settings) => builder.AddListener(new TcpListener(settings)); 46 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc/WebSockets/WebSocketClient.cs: -------------------------------------------------------------------------------- 1 | using System.Net.WebSockets; 2 | namespace UiPath.Rpc.WebSockets; 3 | using ConnectionFactory = Func; 4 | using BeforeCallHandler = Func; 5 | interface IWebSocketsKey : IConnectionKey 6 | { 7 | Uri Uri { get; } 8 | } 9 | class WebSocketClient : ServiceClient, IWebSocketsKey where TInterface : class 10 | { 11 | public WebSocketClient(Uri uri, TimeSpan requestTimeout, ILogger logger, ConnectionFactory connectionFactory, BeforeCallHandler beforeCall, EndpointSettings serviceEndpoint) : base(requestTimeout, logger, connectionFactory, beforeCall, serviceEndpoint) 12 | { 13 | Uri = uri; 14 | HashCode = uri.GetHashCode(); 15 | } 16 | public override string Name => base.Name ?? Uri.ToString(); 17 | public Uri Uri { get; } 18 | public override bool Equals(IConnectionKey other) => other == this || (other is IWebSocketsKey otherClient && Uri.Equals(otherClient.Uri) && base.Equals(other)); 19 | public override ClientConnection CreateClientConnection() => new WebSocketClientConnection(this); 20 | class WebSocketClientConnection : ClientConnection 21 | { 22 | ClientWebSocket _clientWebSocket; 23 | public WebSocketClientConnection(IConnectionKey connectionKey) : base(connectionKey) {} 24 | public override bool Connected => _clientWebSocket?.State == WebSocketState.Open; 25 | protected override void Dispose(bool disposing) 26 | { 27 | _clientWebSocket?.Dispose(); 28 | base.Dispose(disposing); 29 | } 30 | public override async Task Connect(CancellationToken cancellationToken) 31 | { 32 | _clientWebSocket = new(); 33 | var uri = ((IWebSocketsKey)ConnectionKey).Uri; 34 | await _clientWebSocket.ConnectAsync(uri, cancellationToken).ConfigureAwait(false); 35 | return new WebSocketStream(_clientWebSocket); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc/WebSockets/WebSocketClientBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace UiPath.Rpc.WebSockets; 2 | public abstract class WebSocketClientBuilderBase : ServiceClientBuilder where TInterface : class where TDerived : ServiceClientBuilder 3 | { 4 | private readonly Uri _uri; 5 | protected WebSocketClientBuilderBase(Uri uri, Type callbackContract = null, IServiceProvider serviceProvider = null) : base(callbackContract, serviceProvider) => 6 | _uri = uri; 7 | protected override TInterface BuildCore(EndpointSettings serviceEndpoint) => 8 | new WebSocketClient(_uri, _requestTimeout, _logger, _connectionFactory, _beforeCall, serviceEndpoint).CreateProxy(); 9 | } 10 | public class WebSocketClientBuilder : WebSocketClientBuilderBase, TInterface> where TInterface : class 11 | { 12 | public WebSocketClientBuilder(Uri uri) : base(uri){} 13 | } 14 | public class WebSocketClientBuilder : WebSocketClientBuilderBase, TInterface> where TInterface : class where TCallbackInterface : class 15 | { 16 | public WebSocketClientBuilder(Uri uri, IServiceProvider serviceProvider) : base(uri, typeof(TCallbackInterface), serviceProvider) { } 17 | public WebSocketClientBuilder CallbackInstance(TCallbackInterface singleton) 18 | { 19 | _callbackInstance = singleton; 20 | return this; 21 | } 22 | public WebSocketClientBuilder TaskScheduler(TaskScheduler taskScheduler) 23 | { 24 | _taskScheduler = taskScheduler; 25 | return this; 26 | } 27 | } -------------------------------------------------------------------------------- /UiPath.Rpc/UiPath.Rpc/WebSockets/WebSocketListener.cs: -------------------------------------------------------------------------------- 1 | using System.Net.WebSockets; 2 | namespace UiPath.Rpc.WebSockets; 3 | using Accept = Func>; 4 | public class WebSocketSettings : ListenerSettings 5 | { 6 | public WebSocketSettings(Accept accept) : base("") => Accept = accept; 7 | public Accept Accept { get; } 8 | } 9 | class WebSocketListener : Listener 10 | { 11 | public WebSocketListener(ListenerSettings settings) : base(settings){} 12 | protected override ServerConnection CreateServerConnection() => new WebSocketConnection(this); 13 | class WebSocketConnection : ServerConnection 14 | { 15 | public WebSocketConnection(Listener listener) : base(listener){} 16 | public override async Task AcceptClient(CancellationToken cancellationToken) => 17 | new WebSocketStream(await ((WebSocketSettings)_listener.Settings).Accept(cancellationToken).ConfigureAwait(false)); 18 | } 19 | } 20 | public static class WebSocketServiceExtensions 21 | { 22 | public static ServiceHostBuilder UseWebSockets(this ServiceHostBuilder builder, WebSocketSettings settings) => 23 | builder.AddListener(new WebSocketListener(settings)); 24 | } -------------------------------------------------------------------------------- /src/CI/azp-dotnet-dist.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - task: CopyFiles@2 3 | displayName: '$(Label_DotNet) Copy nupkg to $(Build.ArtifactStagingDirectory)' 4 | inputs: 5 | SourceFolder: 'src\UiPath.CoreIpc\bin\$(DotNet_BuildConfiguration)\' 6 | Contents: '*.*nupkg' 7 | TargetFolder: '$(Build.ArtifactStagingDirectory)' 8 | CleanTargetFolder: true 9 | 10 | - task: PublishBuildArtifacts@1 11 | displayName: '$(Label_DotNet) Publish the $(DotNet_ArtifactName) to the pipeline instance' 12 | inputs: 13 | ArtifactName: '$(DotNet_ArtifactName)' 14 | PathtoPublish: '$(Build.ArtifactStagingDirectory)' 15 | ArtifactType: 'Container' 16 | 17 | - task: DotNetCoreCLI@2 18 | displayName: 'dotnet push to UiPath-Internal' 19 | condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) 20 | inputs: 21 | command: push 22 | packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg' 23 | publishVstsFeed: 'Public.Feeds/UiPath-Internal' 24 | 25 | - task: PublishSymbols@2 26 | displayName: 'Publish Symbols to UiPath Azure Artifacts Symbol Server' 27 | condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) 28 | inputs: 29 | symbolsFolder: $(Build.SourcesDirectory) 30 | searchPattern: '**/UiPath.CoreIpc/bin/**/UiPath.CoreIpc.pdb' 31 | symbolServerType: teamServices 32 | indexSources: false -------------------------------------------------------------------------------- /src/CI/azp-dotnet.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - task: DotNetCoreCLI@2 3 | displayName: '$(Label_DotNet) Run unit tests' 4 | inputs: 5 | command: 'test' 6 | projects: '$(DotNet_SessionSolution)' 7 | publishTestResults: true 8 | testRunTitle: '.NET tests' 9 | arguments: ' --configuration $(DotNet_BuildConfiguration) --logger "console;verbosity=detailed" -p:Version="$(FullVersion)" -p:DefineConstantsEx="CI"' -------------------------------------------------------------------------------- /src/CI/azp-initialization.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | 3 | # Read $(Version) from the UiPath.CoreIpc.csproj file 4 | - powershell: | 5 | $xml = [Xml] ( Get-Content $env:DotNet_MainProjectPath ) 6 | $version = [String] $xml.Project.PropertyGroup.Version 7 | $version = $version.Trim() 8 | 9 | Write-Host "##vso[task.setvariable variable=Version;]$version" 10 | 11 | displayName: '$(Label_Initialization) Read $[Version] from the csproj' 12 | env: 13 | DotNet_MainProjectPath: $(DotNet_MainProjectPath) 14 | 15 | # If $(PublishRelease) != "true" then compute $(FullVersion) as $(Version)-$(Build.BuildNumber) 16 | - task: VariableTransformTask@1 17 | displayName: '$(Label_Initialization) Compute $[FullVersion] when $[PublishRelease] is not true' 18 | inputs: 19 | value: '$(Version)-$(Build.BuildNumber)' 20 | variableName: 'FullVersion' 21 | IsSecret: false 22 | transformAction: 'none' 23 | condition: ne(variables['PublishRelease'], 'true') 24 | 25 | # If $(PublishRelease) == "true" then compute $(FullVersion) as $(Version) 26 | - task: VariableTransformTask@1 27 | displayName: '$(Label_Initialization) Compute $[FullVersion] when $[PublishRelease] is "true"' 28 | inputs: 29 | value: '$(Version)' 30 | variableName: 'FullVersion' 31 | IsSecret: false 32 | transformAction: 'none' 33 | condition: eq(variables['PublishRelease'], 'true') 34 | -------------------------------------------------------------------------------- /src/CI/azp-js.publish-npm.steps.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - checkout: none 3 | 4 | - download: current 5 | artifact: 'NPM package' 6 | # The destination path is $(Pipeline.Workspace) 7 | 8 | - task: NodeTool@0 9 | displayName: 'Use Node.js 20.11.0' 10 | inputs: 11 | versionSpec: '20.11.0' 12 | 13 | - task: ExtractFiles@1 14 | displayName: 'Extract Files' 15 | inputs: 16 | archiveFilePatterns: '$(Pipeline.Workspace)/NPM package/*.zip' 17 | destinationFolder: '$(System.DefaultWorkingDirectory)/unzipped' 18 | cleanDestinationFolder: true 19 | 20 | - task: Npm@1 21 | displayName: 'Publish NPM (NodeJS)' 22 | inputs: 23 | command: 'publish' 24 | workingDir: '$(System.DefaultWorkingDirectory)/unzipped/dist/prepack/node' 25 | publishEndpoint: PublishNPM 26 | 27 | - task: Npm@1 28 | displayName: 'Publish NPM (Web)' 29 | inputs: 30 | command: 'publish' 31 | workingDir: '$(System.DefaultWorkingDirectory)/unzipped/dist/prepack/web' 32 | publishEndpoint: PublishNPM 33 | -------------------------------------------------------------------------------- /src/CI/azp-nodejs-dist.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - task: ArchiveFiles@2 3 | displayName: 'Archive the project directory' 4 | inputs: 5 | archiveType: 'zip' 6 | includeRootFolder: false 7 | rootFolderOrFile: '$(NodeJS_ProjectPath)' 8 | archiveFile: '$(NodeJS_ArchivePath)' 9 | 10 | - task: PublishBuildArtifacts@1 11 | displayName: 'Publish the $(NodeJS_ArtifactName) to the pipeline instance' 12 | inputs: 13 | ArtifactName: '$(NodeJS_ArtifactName)' 14 | PathtoPublish: '$(NodeJS_ArchivePath)' 15 | ArtifactType: 'Container' 16 | -------------------------------------------------------------------------------- /src/Clients/js/.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_size = 4 3 | indent_style = space 4 | insert_final_newline = true 5 | end_of_line = crlf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | quote_type = single 9 | max_line_length = 100 10 | -------------------------------------------------------------------------------- /src/Clients/js/.gitignore: -------------------------------------------------------------------------------- 1 | /.vs 2 | /.nyc_output 3 | node_modules 4 | coverage 5 | yarn.lock 6 | dist-packages/**/* 7 | dist 8 | reports 9 | !dist-packages/.gitkeep 10 | .vscode 11 | 12 | # Mac Finder 13 | .DS_Store 14 | -------------------------------------------------------------------------------- /src/Clients/js/.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "src/**/*.ts" 4 | ], 5 | "extension": [ 6 | ".ts", 7 | ".tsx" 8 | ], 9 | "exclude": [ 10 | "**/*.spec.ts", 11 | "**/*.d.ts", 12 | "**/index.ts", 13 | "**/test/**/*", 14 | "**/testing/**/*" 15 | ], 16 | "reporter": [ 17 | "html", 18 | "cobertura", 19 | "text", 20 | "lcovonly" 21 | ], 22 | "report-dir": "./reports/coverage/node/html", 23 | "cache": true, 24 | "all": true 25 | } 26 | -------------------------------------------------------------------------------- /src/Clients/js/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "endOfLine": "crlf", 4 | "arrowParens": "avoid" 5 | } 6 | -------------------------------------------------------------------------------- /src/Clients/js/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "coverage-gutters.coverageBaseDir": "**", 3 | "coverage-gutters.coverageFileNames": ["lcov.info"], 4 | "coverage-gutters.showGutterCoverage": false, 5 | "coverage-gutters.showLineCoverage": true, 6 | "coverage-gutters.partialHighlightLight": "rgba(220, 213, 143, 0.15)", 7 | "coverage-gutters.partialHighlightDark": "rgba(121, 86, 10, 0.15)", 8 | "coverage-gutters.highlightdark": "rgba(45, 121, 10, 0.15)", 9 | "coverage-gutters.highlightlight": "rgba(166, 220, 142, 0.15)", 10 | "coverage-gutters.noHighlightDark": "rgba(121, 31, 10, 0.15)", 11 | "coverage-gutters.noHighlightLight": "rgba(220, 143, 143, 0.15)", 12 | "typescript.tsdk": "node_modules\\typescript\\lib", 13 | 14 | "prettier.singleQuote": true, 15 | 16 | "editor.codeActionsOnSave": { 17 | "source.organizeImports": "never", 18 | "source.fixAll": "explicit" 19 | }, 20 | 21 | "karmaTestExplorer.testFiles": ["test/std/**/*.test.ts", "test/web/**/*.test.ts"], 22 | 23 | "jasmineExplorer.config": "jasmine.node.json", 24 | "jasmineExplorer.nodeArgv": [ 25 | "--experimental-specifier-resolution=node", 26 | "--loader", 27 | "ts-node/esm", 28 | ], 29 | "jasmineExplorer.env": { 30 | "TS_NODE_COMPILER_OPTIONS": "{\"module\":\"ES2022\",\"moduleResolution\":\"node\"}" 31 | }, 32 | 33 | "editor.tokenColorCustomizations": { 34 | "[windows-xp]": { 35 | "textMateRules": [ 36 | { 37 | "scope": "variable.language", 38 | "settings": { 39 | "fontStyle": "italic" 40 | } 41 | } 42 | ] 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Clients/js/assets/js-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/assets/js-16x16.png -------------------------------------------------------------------------------- /src/Clients/js/assets/js-24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/assets/js-24x24.png -------------------------------------------------------------------------------- /src/Clients/js/assets/js-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/assets/js-32x32.png -------------------------------------------------------------------------------- /src/Clients/js/assets/js-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/assets/js-48x48.png -------------------------------------------------------------------------------- /src/Clients/js/assets/node/README.md: -------------------------------------------------------------------------------- 1 | # **![The NPM icon](./npm-32x32.png) UiPath/CoreIpc for NodeJS** (NPM Package) 2 | 3 | -------------------------------------------------------------------------------- /src/Clients/js/assets/node/npm-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/assets/node/npm-32x32.png -------------------------------------------------------------------------------- /src/Clients/js/assets/npm-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/assets/npm-16x16.png -------------------------------------------------------------------------------- /src/Clients/js/assets/npm-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/assets/npm-32x32.png -------------------------------------------------------------------------------- /src/Clients/js/assets/npm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/assets/npm.png -------------------------------------------------------------------------------- /src/Clients/js/assets/npm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Clients/js/assets/web-js/README.md: -------------------------------------------------------------------------------- 1 | # **![The NPM icon](./js-32x32.png) UiPath/CoreIpc for Web** (Self-contained JavaScript bundle) 2 | 3 | -------------------------------------------------------------------------------- /src/Clients/js/assets/web-js/js-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/assets/web-js/js-32x32.png -------------------------------------------------------------------------------- /src/Clients/js/assets/web/README.md: -------------------------------------------------------------------------------- 1 | # **![The NPM icon](./npm-32x32.png) UiPath/CoreIpc for Web** (NPM package) 2 | 3 | -------------------------------------------------------------------------------- /src/Clients/js/assets/web/npm-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/assets/web/npm-32x32.png -------------------------------------------------------------------------------- /src/Clients/js/dist-packages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/dist-packages/.gitkeep -------------------------------------------------------------------------------- /src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30320.27 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiPath.CoreIpc.NodeInterop", "UiPath.CoreIpc.NodeInterop\UiPath.CoreIpc.NodeInterop.csproj", "{B514D2A2-B8ED-4A2A-BDE7-42F74A316FBE}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiPath.CoreIpc", "..\..\..\UiPath.CoreIpc\UiPath.CoreIpc.csproj", "{B53F7E57-886D-4E0F-A5CB-2B66746B021A}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {B514D2A2-B8ED-4A2A-BDE7-42F74A316FBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {B514D2A2-B8ED-4A2A-BDE7-42F74A316FBE}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {B514D2A2-B8ED-4A2A-BDE7-42F74A316FBE}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {B514D2A2-B8ED-4A2A-BDE7-42F74A316FBE}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {B53F7E57-886D-4E0F-A5CB-2B66746B021A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {B53F7E57-886D-4E0F-A5CB-2B66746B021A}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {B53F7E57-886D-4E0F-A5CB-2B66746B021A}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {B53F7E57-886D-4E0F-A5CB-2B66746B021A}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {70F04FE3-6305-4266-AF26-10544077688F} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/CompilerServices.cs: -------------------------------------------------------------------------------- 1 | namespace System.Runtime.CompilerServices; 2 | 3 | /// 4 | /// 5 | [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Field | System.AttributeTargets.Property | System.AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] 6 | public sealed class RequiredMemberAttribute : Attribute { } 7 | 8 | /// 9 | /// Indicates that compiler support for a particular feature is required for the location where this attribute is applied. 10 | /// 11 | [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] 12 | public // polyfill! 13 | sealed class CompilerFeatureRequiredAttribute : Attribute 14 | { 15 | /// 16 | /// The used for the ref structs C# feature. 17 | /// 18 | public const string RefStructs = nameof(RefStructs); 19 | 20 | /// 21 | /// The used for the required members C# feature. 22 | /// 23 | public const string RequiredMembers = nameof(RequiredMembers); 24 | 25 | /// 26 | /// Initializes a new instance of the class. 27 | /// 28 | /// The name of the required compiler feature. 29 | public CompilerFeatureRequiredAttribute(string featureName) 30 | { 31 | FeatureName = featureName; 32 | } 33 | 34 | /// 35 | /// Gets the name of the compiler feature. 36 | /// 37 | public string FeatureName { get; } 38 | 39 | /// 40 | /// Gets a value indicating whether the compiler can choose to allow access to the location where this attribute is applied 41 | /// if it does not understand . 42 | /// 43 | public bool IsOptional { get; init; } 44 | } 45 | 46 | internal static class IsExternalInit 47 | { 48 | } 49 | -------------------------------------------------------------------------------- /src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Contracts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace UiPath.CoreIpc.NodeInterop; 6 | 7 | internal static class Contracts 8 | { 9 | public interface IArithmetic 10 | { 11 | Task Sum(int x, int y); 12 | Task SendMessage(Message message); 13 | } 14 | 15 | public interface IAlgebra 16 | { 17 | Task Ping(); 18 | Task MultiplySimple(int x, int y); 19 | Task Multiply(int x, int y, Message message = default!); 20 | Task Sleep(int milliseconds, Message message = default!, CancellationToken ct = default); 21 | Task Timeout(); 22 | Task Echo(int x); 23 | Task TestMessage(Message message); 24 | } 25 | 26 | public interface ICalculus 27 | { 28 | Task Ping(); 29 | } 30 | 31 | public interface IBrittleService 32 | { 33 | Task Sum(int x, int y, TimeSpan delay, DateTime? crashBeforeUtc); 34 | 35 | Task Kill(); 36 | } 37 | 38 | public interface IEnvironmentVariableGetter 39 | { 40 | Task Get(string variable); 41 | } 42 | 43 | public interface IDtoService 44 | { 45 | Task ReturnDto(Dto dto); 46 | } 47 | public class Dto 48 | { 49 | public bool BoolProperty { get; set; } 50 | public int IntProperty { get; set; } 51 | public string StringProperty { get; set; } 52 | 53 | public Dto(bool boolProperty, int intProperty, string stringProperty) 54 | { 55 | BoolProperty = boolProperty; 56 | IntProperty = intProperty; 57 | StringProperty = stringProperty; 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "UiPath.CoreIpc.NodeInterop": { 4 | "commandName": "Project", 5 | "commandLineArgs": "--websocket ws://127.0.0.1:61234 --pipe uipath-coreipc-test-pipe" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/Signalling.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Converters; 3 | using System; 4 | 5 | namespace UiPath.CoreIpc.NodeInterop; 6 | 7 | internal static class Signalling 8 | { 9 | 10 | [JsonConverter(typeof(StringEnumConverter))] 11 | public enum SignalKind 12 | { 13 | Throw, 14 | PoweringOn, 15 | ReadyToConnect, 16 | } 17 | 18 | public class Signal 19 | { 20 | public static implicit operator Signal(SignalKind signalKind) => new Signal { Kind = signalKind }; 21 | public SignalKind Kind { get; set; } 22 | } 23 | 24 | public class Signal : Signal 25 | { 26 | public required TDetails Details { get; init; } 27 | } 28 | 29 | public static Signal MakeSignal(SignalKind kind, TDetails details) => new Signal 30 | { 31 | Kind = kind, 32 | Details = details 33 | }; 34 | 35 | public static void Send(Signal signal) => Console.WriteLine($"###{JsonConvert.SerializeObject(signal)}"); 36 | 37 | public static void Throw(Exception exception) 38 | => Send(MakeSignal(SignalKind.Throw, new 39 | { 40 | Type = exception.GetType().Name, 41 | Message = exception.Message 42 | })); 43 | 44 | public static void CannotConnect(Exception exception) 45 | => Send(MakeSignal(SignalKind.ReadyToConnect, new 46 | { 47 | Type = exception.GetType().Name, 48 | Message = exception.Message 49 | })); 50 | } 51 | -------------------------------------------------------------------------------- /src/Clients/js/dotnet/UiPath.CoreIpc.NodeInterop/UiPath.CoreIpc.NodeInterop.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net461;net6.0 5 | Exe 6 | preview 7 | true 8 | enable 9 | 1998 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Clients/js/jasmine-console-reporter.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'jasmine-console-reporter'; 2 | -------------------------------------------------------------------------------- /src/Clients/js/jasmine.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "reporters": [ 3 | { 4 | "name": "jasmine-console-reporter", 5 | "options": { 6 | "colors": true, 7 | "listStyle": "indent" 8 | } 9 | } 10 | ], 11 | "spec_dir": "test", 12 | "spec_files": ["std/**/*test.ts", "node/**/*test.ts"], 13 | "env": { 14 | "random": false 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Clients/js/jasmine.node.ts: -------------------------------------------------------------------------------- 1 | import Jasmine from 'jasmine'; 2 | import JasmineConsoleReporter from 'jasmine-console-reporter'; 3 | import { JUnitXmlReporter } from 'jasmine-reporters'; 4 | 5 | async function main() { 6 | const jasmine = new Jasmine(); 7 | 8 | jasmine.loadConfigFile('./jasmine.node.json'); 9 | 10 | jasmine.env.clearReporters(); 11 | jasmine.addReporter( 12 | new JasmineConsoleReporter({ 13 | colors: true, 14 | cleanStack: true, 15 | listStyle: 'indent', 16 | timeUnit: 'ms', 17 | emoji: true, 18 | activity: true, 19 | }), 20 | ); 21 | 22 | jasmine.addReporter( 23 | new JUnitXmlReporter({ 24 | savePath: 'reports/test/node', 25 | consolidateAll: true, 26 | }), 27 | ); 28 | 29 | jasmine.exitOnCompletion = true; 30 | await jasmine.execute(); 31 | } 32 | 33 | main(); 34 | -------------------------------------------------------------------------------- /src/Clients/js/readme-assets/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/readme-assets/diagram.png -------------------------------------------------------------------------------- /src/Clients/js/readme-assets/dotnet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/readme-assets/dotnet.png -------------------------------------------------------------------------------- /src/Clients/js/readme-assets/nodejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/readme-assets/nodejs.png -------------------------------------------------------------------------------- /src/Clients/js/readme-assets/npm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/readme-assets/npm.png -------------------------------------------------------------------------------- /src/Clients/js/readme-assets/nuget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UiPath/coreipc/8e0b232ec7547c5af8d8f92990aa0c0ecf9ba342/src/Clients/js/readme-assets/nuget.png -------------------------------------------------------------------------------- /src/Clients/js/republish.bat: -------------------------------------------------------------------------------- 1 | echo Rebuilding @uipath/coreipc and @uipath/coreipc-web 2 | call npm run build 3 | 4 | cd ./dist/prepack/node 5 | echo Unpublishing @uipath/coreipc 6 | call npm unpublish --force --registry http://localhost:4873/ 7 | echo Republishing @uipath/coreipc 8 | call npm publish --registry http://localhost:4873/ 9 | 10 | echo Doing it 11 | cd ../web 12 | echo Unpublishing @uipath/coreipc-web 13 | call npm unpublish --force --registry http://localhost:4873/ 14 | echo Republishing @uipath/coreipc-web 15 | call npm publish --registry http://localhost:4873/ 16 | 17 | cd ../.. 18 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/Ipc.ts: -------------------------------------------------------------------------------- 1 | import { IpcBaseImpl, AddressSelectionDelegate, IpcBase } from '../std'; 2 | import { NodeAddressBuilder } from './NodeAddressBuilder'; 3 | 4 | /* @internal */ 5 | export class IpcNodeImpl extends IpcBaseImpl implements Ipc { 6 | constructor() { 7 | super(NodeAddressBuilder); 8 | } 9 | 10 | public namedPipe(name: string): AddressSelectionDelegate { 11 | return builder => builder.isPipe(name); 12 | } 13 | } 14 | 15 | export interface Ipc extends IpcBase { 16 | namedPipe(name: string): AddressSelectionDelegate; 17 | } 18 | 19 | export const ipc: Ipc = new IpcNodeImpl(); 20 | 21 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/NodeAddressBuilder.ts: -------------------------------------------------------------------------------- 1 | import { AddressBuilder } from '../std'; 2 | import { NamedPipeAddress, NodeWebSocketAddress } from './Transport'; 3 | 4 | export class NodeAddressBuilder extends AddressBuilder { 5 | public isPipe(name: string): void { 6 | this._address = new NamedPipeAddress(name); 7 | } 8 | 9 | public isWebSocket(url: string): void { 10 | this._address = new NodeWebSocketAddress(url); 11 | } 12 | 13 | /* @internal */ 14 | public assertAddress(): NamedPipeAddress | NodeWebSocketAddress { 15 | if (this._address instanceof NamedPipeAddress || 16 | this._address instanceof NodeWebSocketAddress) { 17 | return this._address; 18 | } 19 | 20 | throw new Error('Neither method isPipe nor isWebSocket was called in the address callback.'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/Transport/NamedPipes/NamedPipeAddress.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Address, 3 | CancellationToken, 4 | ConnectHelper, 5 | Socket, 6 | TimeSpan, 7 | } from '../../../std'; 8 | import { NamedPipeSocket } from './NamedPipeSocket'; 9 | 10 | export class NamedPipeAddress extends Address { 11 | constructor(public readonly name: string) { 12 | super(); 13 | } 14 | 15 | public override get key() { 16 | return `namedpipe:${this.name}`; 17 | } 18 | 19 | public override async connect(helper: ConnectHelper, timeout: TimeSpan, ct: CancellationToken): Promise { 20 | return await NamedPipeSocket.connectWithHelper(helper, this.name, timeout, ct); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/Transport/NamedPipes/NamedPipeSocketLike.ts: -------------------------------------------------------------------------------- 1 | /* @internal */ 2 | export interface NamedPipeSocketLike { 3 | once(event: 'error', listener: (error: Error) => void): this; 4 | on(event: 'end', listener: () => void): this; 5 | on(event: 'data', listener: (data: Buffer) => void): this; 6 | 7 | connect(path: string, connectionListener?: () => void): this; 8 | write(buffer: Uint8Array | string, cb?: (err?: Error) => void): boolean; 9 | 10 | removeAllListeners(event?: string | symbol): this; 11 | unref(): void; 12 | destroy(error?: Error): void; 13 | } 14 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/Transport/NamedPipes/NamedPipeSocketLikeCtor.ts: -------------------------------------------------------------------------------- 1 | import { NamedPipeSocketLike } from '.'; 2 | 3 | /* @internal */ 4 | export type NamedPipeSocketLikeCtor = new () => NamedPipeSocketLike; 5 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/Transport/NamedPipes/index.ts: -------------------------------------------------------------------------------- 1 | export * from './NamedPipeAddress'; 2 | export * from './NamedPipeSocket'; 3 | export * from './NamedPipeSocketLike'; 4 | export * from './NamedPipeSocketLikeCtor'; 5 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/Transport/WebSockets/NodeWebSocketAddress.ts: -------------------------------------------------------------------------------- 1 | import { NodeWebSocket } from '.'; 2 | import { TimeSpan, CancellationToken, Socket, ConnectHelper, Address } from '../../../std'; 3 | 4 | export class NodeWebSocketAddress extends Address { 5 | constructor(public readonly url: string) { 6 | super(); 7 | } 8 | 9 | public override get key() { 10 | return `websocket:${this.url}`; 11 | } 12 | 13 | public override async connect(helper: ConnectHelper, timeout: TimeSpan, ct: CancellationToken): Promise { 14 | return await NodeWebSocket.connectWithHelper(helper, this.url, timeout, ct); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/Transport/WebSockets/NodeWebSocketError.ts: -------------------------------------------------------------------------------- 1 | import { CoreIpcError } from '../../../std'; 2 | import { NodeWebSocketLike } from '.'; 3 | 4 | export class NodeWebSocketError extends CoreIpcError {} 5 | 6 | export module NodeWebSocketError { 7 | export class ConnectFailure extends NodeWebSocketError { 8 | constructor( 9 | public readonly socket: NodeWebSocketLike, 10 | public readonly innerError: any, 11 | message?: string, 12 | ) { 13 | super(message ?? ConnectFailure.defaultMessage); 14 | } 15 | 16 | private static readonly defaultMessage = 17 | 'Received an error while awaiting for a WebSocket to connect.'; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/Transport/WebSockets/NodeWebSocketLike.ts: -------------------------------------------------------------------------------- 1 | import WebSocket from 'ws'; 2 | 3 | /* @internal */ 4 | export interface NodeWebSocketLike { 5 | binaryType: 'nodebuffer' | 'arraybuffer' | 'fragments'; 6 | 7 | send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void; 8 | close(code?: number, reason?: string): void; 9 | 10 | onopen: ((event: WebSocket.Event) => void) | null; 11 | onerror: ((event: WebSocket.ErrorEvent) => void) | null; 12 | onclose: ((event: WebSocket.CloseEvent) => void) | null; 13 | onmessage: ((event: WebSocket.MessageEvent) => void) | null; 14 | } 15 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/Transport/WebSockets/NodeWebSocketLikeCtor.ts: -------------------------------------------------------------------------------- 1 | import { NodeWebSocketLike } from '.'; 2 | 3 | /* @internal */ 4 | export type NodeWebSocketLikeCtor = new ( 5 | url: string | URL, 6 | protocols?: string | string[], 7 | ) => NodeWebSocketLike; 8 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/Transport/WebSockets/index.ts: -------------------------------------------------------------------------------- 1 | export * from './NodeWebSocket'; 2 | export * from './NodeWebSocketAddress'; 3 | export * from './NodeWebSocketLike'; 4 | export * from './NodeWebSocketLikeCtor'; 5 | export * from './NodeWebSocketError'; 6 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/Transport/index.ts: -------------------------------------------------------------------------------- 1 | export * from './NamedPipes'; 2 | export * from './WebSockets'; 3 | -------------------------------------------------------------------------------- /src/Clients/js/src/node/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Platform'; 2 | export * from './Transport'; 3 | export * from './Ipc'; 4 | export * from '../std'; 5 | export * from './NodeAddressBuilder'; 6 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/cancellation/CancellationToken.ts: -------------------------------------------------------------------------------- 1 | import { EmptyCancellationToken, CancellationTokenRegistration } from '.'; 2 | import { Trace } from '..'; 3 | import { PromiseCompletionSource, PromisePal } from '../promises'; 4 | 5 | export abstract class CancellationToken { 6 | public static get none(): CancellationToken { 7 | return EmptyCancellationToken.instance; 8 | } 9 | 10 | protected constructor() {} 11 | 12 | public abstract get canBeCanceled(): boolean; 13 | public abstract get isCancellationRequested(): boolean; 14 | public abstract throwIfCancellationRequested(): void | never; 15 | public abstract register(callback: () => void): CancellationTokenRegistration; 16 | 17 | public bind(pcs: PromiseCompletionSource): void { 18 | if (this.isCancellationRequested) { 19 | pcs.trySetCanceled(); 20 | return; 21 | } 22 | if (!this.canBeCanceled) { 23 | return; 24 | } 25 | 26 | const reg = this.register(() => pcs.trySetCanceled()); 27 | Trace.traceErrorNoThrow( 28 | (async () => { 29 | try { 30 | await pcs.promise; 31 | } finally { 32 | reg.dispose(); 33 | } 34 | })(), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/cancellation/CancellationTokenRegistration.ts: -------------------------------------------------------------------------------- 1 | import { IDisposable, assertArgument } from '..'; 2 | import { CancellationTokenSource } from '.'; 3 | 4 | export abstract class CancellationTokenRegistration implements IDisposable { 5 | public abstract dispose(): void; 6 | } 7 | 8 | /* @internal */ 9 | export class ProperCancellationTokenRegistration extends CancellationTokenRegistration { 10 | constructor(source: CancellationTokenSource, callback: () => void); 11 | constructor( 12 | private readonly _source: CancellationTokenSource, 13 | private readonly _callback: () => void, 14 | ) { 15 | super(); 16 | assertArgument({ _source }, CancellationTokenSource); 17 | assertArgument({ _callback }, 'function'); 18 | } 19 | 20 | public dispose(): void { 21 | this._source.unregister(this._callback); 22 | } 23 | } 24 | 25 | /* @internal */ 26 | export class EmptyCancellationTokenRegistration extends CancellationTokenRegistration { 27 | public static readonly instance = new EmptyCancellationTokenRegistration(); 28 | 29 | private constructor() { 30 | super(); 31 | } 32 | 33 | public dispose(): void {} 34 | } 35 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/cancellation/EmptyCancellationToken.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CancellationToken, 3 | CancellationTokenRegistration, 4 | EmptyCancellationTokenRegistration, 5 | } from '.'; 6 | 7 | import { assertArgument } from '..'; 8 | 9 | /* @internal */ 10 | export class EmptyCancellationToken extends CancellationToken { 11 | public static readonly instance = new EmptyCancellationToken(); 12 | 13 | private constructor() { 14 | super(); 15 | } 16 | 17 | public get canBeCanceled(): boolean { 18 | return false; 19 | } 20 | 21 | public get isCancellationRequested(): boolean { 22 | return false; 23 | } 24 | 25 | public throwIfCancellationRequested(): void {} 26 | 27 | public register(callback: () => void): CancellationTokenRegistration { 28 | assertArgument({ callback }, 'function'); 29 | 30 | return EmptyCancellationTokenRegistration.instance; 31 | } 32 | 33 | public toString() { 34 | return 'CancellationToken.none'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/cancellation/LinkedCancellationTokenSource.ts: -------------------------------------------------------------------------------- 1 | import { IDisposable } from '..'; 2 | import { CancellationTokenSource } from '.'; 3 | 4 | /* @internal */ 5 | export class LinkedCancellationTokenSource extends CancellationTokenSource { 6 | constructor(private readonly _registration: IDisposable) { 7 | super(); 8 | } 9 | 10 | public dispose(): void { 11 | if (this._isDisposed) { 12 | return; 13 | } 14 | 15 | super.dispose(); 16 | this._registration.dispose(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/cancellation/RandomCancellationToken.ts: -------------------------------------------------------------------------------- 1 | import { CancellationToken, CancellationTokenSource } from '.'; 2 | 3 | import { IDisposable, assertArgument, OperationCanceledError } from '..'; 4 | 5 | /* @internal */ 6 | export class RandomCancellationToken extends CancellationToken { 7 | public constructor(private readonly _source: CancellationTokenSource) { 8 | super(); 9 | } 10 | 11 | public get canBeCanceled(): boolean { 12 | return true; 13 | } 14 | 15 | public get isCancellationRequested(): boolean { 16 | return this._source.isCancellationRequested; 17 | } 18 | 19 | public throwIfCancellationRequested(): void { 20 | if (this._source.isCancellationRequested) { 21 | throw new OperationCanceledError(); 22 | } 23 | } 24 | 25 | public register(callback: () => void): IDisposable { 26 | assertArgument({ callback }, 'function'); 27 | 28 | return this._source.registerUnchecked(callback); 29 | } 30 | 31 | public static toString() { 32 | return 'new CancellationToken()'; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/cancellation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CancellationTokenSource'; 2 | export * from './CancellationTokenRegistration'; 3 | export * from './CancellationToken'; 4 | export * from './EmptyCancellationToken'; 5 | export * from './RandomCancellationToken'; 6 | export * from './LinkedCancellationTokenSource'; 7 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/collections/ConditionalWeakTable.ts: -------------------------------------------------------------------------------- 1 | import { assertArgument } from "../helpers"; 2 | 3 | export class ConditionalWeakTable { 4 | private readonly _symbol = Symbol(); 5 | 6 | public getOrCreateValue(key: K, factory: (key: K) => V): V { 7 | assertArgument({ key }, 'object', 'function'); 8 | assertArgument({ factory }, 'function'); 9 | 10 | return (key as any)[this._symbol] ??= factory(key); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/collections/Dictionary.ts: -------------------------------------------------------------------------------- 1 | export class Dictionary { 2 | public static create(): Dictionary { 3 | return new Dictionary(); 4 | } 5 | 6 | private readonly _map = new Map(); 7 | 8 | public getOrCreateValue(key: K, factory: (key: K) => V): V { 9 | if (this._map.has(key)) { 10 | return this._map.get(key)!; 11 | } 12 | 13 | let value = factory(key); 14 | this._map.set(key, value); 15 | return value; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/collections/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ConditionalWeakTable'; 2 | export * from './Dictionary'; 3 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/diagnostics/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Trace'; 2 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/disposable/AggregateDisposable.ts: -------------------------------------------------------------------------------- 1 | import { assertArgument, AggregateError, ArgumentError, UnknownError } from '..'; 2 | import { IDisposable } from '.'; 3 | 4 | /* @internal */ 5 | export class AggregateDisposable implements IDisposable { 6 | public static maybeCreate(...disposables: IDisposable[]): AggregateDisposable | null { 7 | if (disposables.length === 0) { 8 | return null; 9 | } 10 | 11 | return new AggregateDisposable(...disposables); 12 | } 13 | 14 | private readonly _disposables: IDisposable[]; 15 | 16 | public constructor(...disposables: IDisposable[]) { 17 | assertArgument({ disposables }, Array); 18 | 19 | if (disposables.length === 0) { 20 | throw new ArgumentError('No disposables were supplied.'); 21 | } 22 | 23 | if (disposables.filter(x => typeof x['dispose'] !== 'function').length !== 0) { 24 | throw new ArgumentError('At least one supplied item is not an IDispoable.'); 25 | } 26 | 27 | this._disposables = disposables; 28 | } 29 | 30 | public dispose(): void { 31 | const errors = new Array(); 32 | for (const disposable of this._disposables) { 33 | try { 34 | disposable.dispose(); 35 | } catch (error) { 36 | errors.push(UnknownError.ensureError(error)); 37 | } 38 | } 39 | if (errors.length > 0) { 40 | throw new AggregateError(undefined, ...errors); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/disposable/IAsyncDisposable.ts: -------------------------------------------------------------------------------- 1 | export interface IAsyncDisposable { 2 | disposeAsync(): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/disposable/IDisposable.ts: -------------------------------------------------------------------------------- 1 | export interface IDisposable { 2 | dispose(): void; 3 | } 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/disposable/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IDisposable'; 2 | export * from './IAsyncDisposable'; 3 | export * from './AggregateDisposable'; 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/AggregateError.ts: -------------------------------------------------------------------------------- 1 | import { assertArgument } from '..'; 2 | import { CoreIpcError, ArgumentOutOfRangeError } from '.'; 3 | 4 | export class AggregateError extends CoreIpcError { 5 | public static maybeAggregate(...errors: Error[]): Error | undefined { 6 | if (errors.filter((x) => !(x instanceof Error)).length > 0) { 7 | throw new ArgumentOutOfRangeError( 8 | 'errors', 9 | `Specified argument contained at least one element which is not an Error.`, 10 | ); 11 | } 12 | 13 | switch (errors.length) { 14 | case 0: 15 | return undefined; 16 | case 1: 17 | return errors[0]; 18 | default: 19 | return new AggregateError(undefined, ...errors); 20 | } 21 | } 22 | 23 | constructor(message?: string, ...errors: Error[]) { 24 | super(AggregateError.computeFullMessage(message, ...errors)); 25 | this.errors = errors; 26 | } 27 | 28 | public readonly errors: Error[]; 29 | 30 | private static computeFullMessage(message?: string, ...errors: Error[]): string { 31 | assertArgument({ message }, 'undefined', 'string'); 32 | 33 | if (errors.filter((x) => !(x instanceof Error)).length > 0) { 34 | throw new ArgumentOutOfRangeError( 35 | 'errors', 36 | `Specified argument contained at least one element which is not an Error.`, 37 | ); 38 | } 39 | 40 | message = message ?? 'One or more errors occurred.'; 41 | if (errors.length > 0) { 42 | const strErrors = errors.map((error) => `(${error.message})`).join(' '); 43 | message = `${message} ${strErrors}`; 44 | } 45 | return message; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/ArgumentError.ts: -------------------------------------------------------------------------------- 1 | import { ArgumentErrorBase } from '.'; 2 | 3 | export class ArgumentError extends ArgumentErrorBase { 4 | constructor(message?: string, public readonly paramName?: string) { 5 | super('Value does not fall within the expected range.', message, paramName); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/ArgumentErrorBase.ts: -------------------------------------------------------------------------------- 1 | import { CoreIpcError } from '.'; 2 | 3 | export abstract class ArgumentErrorBase extends CoreIpcError { 4 | protected constructor( 5 | fallbackMessage: string, 6 | message?: string, 7 | public readonly paramName?: string, 8 | ) { 9 | super(ArgumentErrorBase.computeFullMessage(fallbackMessage, message, paramName)); 10 | } 11 | 12 | protected static computeFullMessage( 13 | fallbackMessage: string, 14 | message?: string, 15 | paramName?: string, 16 | ): string { 17 | message = message ?? fallbackMessage; 18 | return !paramName ? message : `${message} (Parameter: '${paramName}')`; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/ArgumentNullError.ts: -------------------------------------------------------------------------------- 1 | import { ArgumentErrorBase } from '.'; 2 | 3 | export class ArgumentNullError extends ArgumentErrorBase { 4 | constructor(paramName?: string, message?: string) { 5 | super('Value cannot be null.', message, paramName); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/ArgumentOutOfRangeError.ts: -------------------------------------------------------------------------------- 1 | import { ArgumentErrorBase } from '.'; 2 | 3 | export class ArgumentOutOfRangeError extends ArgumentErrorBase { 4 | constructor(paramName?: string, message?: string) { 5 | super('Specified argument was out of the range of valid values.', message, paramName); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/CoreIpcError.ts: -------------------------------------------------------------------------------- 1 | export class CoreIpcError extends Error { 2 | constructor(message?: string) { 3 | super(message); 4 | this.name = 'CoreIpcError'; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/EndOfStreamError.ts: -------------------------------------------------------------------------------- 1 | import { CoreIpcError } from '.'; 2 | 3 | export class EndOfStreamError extends CoreIpcError { 4 | constructor() { 5 | super('Attempted to read past the end of the stream.'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/InvalidOperationError.ts: -------------------------------------------------------------------------------- 1 | import { CoreIpcError } from '.'; 2 | import { assertArgument } from '../helpers'; 3 | 4 | export class InvalidOperationError extends CoreIpcError { 5 | constructor(message?: string) { 6 | super(InvalidOperationError.computeFullMessage(message)); 7 | } 8 | 9 | private static computeFullMessage(message?: string): string { 10 | assertArgument({ message }, 'undefined', 'string'); 11 | 12 | return message ?? 'Operation is not valid due to the current state of the object.'; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/ObjectDisposedError.ts: -------------------------------------------------------------------------------- 1 | import { CoreIpcError } from '.'; 2 | import { assertArgument } from '..'; 3 | 4 | export class ObjectDisposedError extends CoreIpcError { 5 | constructor(objectName?: string, message?: string) { 6 | super(ObjectDisposedError.computeFullMessage(objectName, message)); 7 | 8 | this.objectName = objectName ?? null; 9 | } 10 | 11 | public readonly objectName: string | null; 12 | 13 | private static computeFullMessage(objectName?: string, message?: string): string { 14 | assertArgument({ objectName }, 'undefined', 'string'); 15 | assertArgument({ message }, 'undefined', 'string'); 16 | 17 | message = message ?? 'Cannot access a disposed object.'; 18 | if (objectName) { 19 | message = `${message}\r\nObject name: '${objectName}'.`; 20 | } 21 | return message; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/OperationCanceledError.ts: -------------------------------------------------------------------------------- 1 | import { CoreIpcError } from '.'; 2 | 3 | export class OperationCanceledError extends CoreIpcError { 4 | constructor() { 5 | super('The operation was canceled.'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/PlatformNotSupportedError.ts: -------------------------------------------------------------------------------- 1 | import { CoreIpcError } from '.'; 2 | 3 | export class PlatformNotSupportedError extends CoreIpcError { 4 | constructor(message?: string) { 5 | super(message ?? PlatformNotSupportedError.defaultMessage); 6 | } 7 | 8 | private static readonly defaultMessage = 'Operation is not supported on this platform.'; 9 | } 10 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/TimeoutError.ts: -------------------------------------------------------------------------------- 1 | import { CoreIpcError } from '.'; 2 | 3 | export class TimeoutError extends CoreIpcError { 4 | constructor(args?: { reportedByServer: boolean }) { 5 | super('The operation has timed out.'); 6 | this.name = 'TimeoutError'; 7 | this.reportedByServer = args?.reportedByServer ?? false; 8 | } 9 | 10 | public readonly reportedByServer: boolean; 11 | } 12 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/UnknownError.ts: -------------------------------------------------------------------------------- 1 | import { CoreIpcError } from '.'; 2 | 3 | export class UnknownError extends CoreIpcError { 4 | public static ensureError(error: any): Error { 5 | if (error instanceof Error) { 6 | return error; 7 | } 8 | 9 | return new UnknownError(error); 10 | } 11 | 12 | constructor(public readonly inner: any) { 13 | super(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/errors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CoreIpcError'; 2 | export * from './ArgumentErrorBase'; 3 | export * from './ArgumentNullError'; 4 | export * from './ArgumentError'; 5 | export * from './ArgumentOutOfRangeError'; 6 | export * from './TimeoutError'; 7 | export * from './InvalidOperationError'; 8 | export * from './OperationCanceledError'; 9 | export * from './AggregateError'; 10 | export * from './UnknownError'; 11 | export * from './ObjectDisposedError'; 12 | export * from './EndOfStreamError'; 13 | export * from './PlatformNotSupportedError'; 14 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './argumentIs'; 2 | export * from './nameof'; 3 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/helpers/nameof.ts: -------------------------------------------------------------------------------- 1 | export function nameof(wrapper: { [key: string]: any }): string { 2 | return Object.keys(wrapper)[0]; 3 | } 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/index.ts: -------------------------------------------------------------------------------- 1 | export * from './errors'; 2 | export * from './helpers'; 3 | export * from './promises'; 4 | export * from './time'; 5 | export * from './disposable'; 6 | export * from './cancellation'; 7 | export * from './io'; 8 | export * from './diagnostics'; 9 | export * from './reflection'; 10 | export * from './serialization'; 11 | export * from './synchronization'; 12 | export * from './system'; 13 | export * from './collections'; 14 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/io/BitConverter.ts: -------------------------------------------------------------------------------- 1 | import { Marshal, SupportedConversion, ArgumentOutOfRangeError } from '..'; 2 | 3 | /* @internal */ 4 | export class BitConverter { 5 | public static getBytes(value: number, type: 'int32le'): Buffer; 6 | public static getBytes(value: number, type: 'uint8'): Buffer; 7 | 8 | public static getBytes(value: unknown, type: SupportedConversion): Buffer { 9 | const buffer = Buffer.alloc(Marshal.sizeOf(type)); 10 | 11 | switch (type) { 12 | case 'int32le': 13 | buffer.writeInt32LE(value as number, 0); 14 | break; 15 | default: 16 | buffer.writeUInt8(value as number, 0); 17 | break; 18 | } 19 | 20 | return buffer; 21 | } 22 | 23 | public static getNumber(buffer: Buffer, type: 'int32le', offset?: number): number; 24 | public static getNumber(buffer: Buffer, type: 'uint8', offset?: number): number; 25 | 26 | public static getNumber(buffer: Buffer, type: SupportedConversion): number { 27 | switch (type) { 28 | case 'int32le': 29 | return buffer.readInt32LE(0); 30 | case 'uint8': 31 | return buffer.readUInt8(0); 32 | 33 | default: 34 | throw new ArgumentOutOfRangeError('type'); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/io/Marshal.ts: -------------------------------------------------------------------------------- 1 | import { SupportedConversion, ArgumentOutOfRangeError } from '..'; 2 | 3 | /* @internal */ 4 | export class Marshal { 5 | public static sizeOf(type: SupportedConversion): number { 6 | switch (type) { 7 | case 'int32le': 8 | return 4; 9 | case 'uint8': 10 | return 1; 11 | 12 | default: 13 | throw new ArgumentOutOfRangeError('type'); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/io/Socket.ts: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs'; 2 | import { CancellationToken, IDisposable } from '../..'; 3 | 4 | export abstract class Socket implements IDisposable { 5 | public abstract get $data(): Observable; 6 | public abstract write(buffer: Buffer, ct: CancellationToken): Promise; 7 | public abstract dispose(): void; 8 | } 9 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/io/Stream.ts: -------------------------------------------------------------------------------- 1 | import { CancellationToken, IDisposable } from '..'; 2 | 3 | /* @internal */ 4 | export abstract class Stream implements IDisposable { 5 | public abstract write(buffer: Buffer, ct: CancellationToken): Promise; 6 | public abstract read( 7 | buffer: Buffer, 8 | offset: number, 9 | length: number, 10 | ct: CancellationToken, 11 | ): Promise; 12 | public abstract dispose(): void; 13 | } 14 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/io/SupportedConversion.ts: -------------------------------------------------------------------------------- 1 | /* @internal */ 2 | export type SupportedConversion = 'int32le' | 'uint8'; 3 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/io/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Stream'; 2 | export * from './SocketStream'; 3 | export * from './Socket'; 4 | export * from './BitConverter'; 5 | export * from './Marshal'; 6 | export * from './SupportedConversion'; 7 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/promises/FinalState.ts: -------------------------------------------------------------------------------- 1 | export abstract class FinalStateBase { 2 | public abstract get kind(): FinalStateKind; 3 | 4 | public isRanToCompletion(): this is FinalStateRanToCompletion { 5 | return this.kind === FinalStateKind.RanToCompletion; 6 | } 7 | 8 | public isFaulted(): this is FinalStateFaulted { 9 | return this.kind === FinalStateKind.Faulted; 10 | } 11 | 12 | public isCanceled(): this is FinalStateCanceled { 13 | return this.kind === FinalStateKind.Canceled; 14 | } 15 | } 16 | 17 | export type FinalState = 18 | | FinalStateRanToCompletion 19 | | FinalStateFaulted 20 | | FinalStateCanceled; 21 | 22 | // tslint:disable-next-line: no-namespace no-internal-module 23 | export module FinalState { 24 | export function ranToCompletion(result: T): FinalStateBase { 25 | return new FinalStateRanToCompletion(result); 26 | } 27 | 28 | export function faulted(error: Error): FinalStateBase { 29 | return new FinalStateFaulted(error); 30 | } 31 | 32 | export function canceled(): FinalStateBase { 33 | return new FinalStateCanceled(); 34 | } 35 | } 36 | 37 | export class FinalStateRanToCompletion extends FinalStateBase { 38 | public constructor(public readonly result: T) { 39 | super(); 40 | } 41 | 42 | public get kind(): FinalStateKind { 43 | return FinalStateKind.RanToCompletion; 44 | } 45 | } 46 | 47 | export class FinalStateFaulted extends FinalStateBase { 48 | public constructor(public readonly error: Error) { 49 | super(); 50 | } 51 | 52 | public get kind(): FinalStateKind { 53 | return FinalStateKind.Faulted; 54 | } 55 | } 56 | 57 | export class FinalStateCanceled extends FinalStateBase { 58 | public get kind(): FinalStateKind { 59 | return FinalStateKind.Canceled; 60 | } 61 | } 62 | 63 | export enum FinalStateKind { 64 | RanToCompletion, 65 | Faulted, 66 | Canceled, 67 | } 68 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/promises/PromiseCompletionSource.ts: -------------------------------------------------------------------------------- 1 | import { assertArgument } from '../helpers'; 2 | import { FinalState, PromiseCompletionSourceInternal, IPromiseCompletionSourceInternal } from '.'; 3 | 4 | export interface IPromiseCompletionSource { 5 | setResult(result: T): void | never; 6 | setFaulted(error: Error): void | never; 7 | setCanceled(): void | never; 8 | 9 | trySetResult(result: T): boolean; 10 | trySetFaulted(error: Error): boolean; 11 | trySetCanceled(): boolean; 12 | } 13 | 14 | export class PromiseCompletionSource { 15 | /* @internal */ 16 | public readonly _internal: IPromiseCompletionSourceInternal; 17 | 18 | public constructor(internal?: any) { 19 | assertArgument({ internal }, 'undefined', 'object'); 20 | 21 | this._internal = internal ?? new PromiseCompletionSourceInternal(); 22 | } 23 | 24 | public get promise(): Promise { 25 | return this._internal.promise; 26 | } 27 | 28 | public setFinalState(finalState: FinalState): void { 29 | this._internal.setFinalState(finalState); 30 | } 31 | public trySetFinalState(finalState: FinalState): boolean { 32 | return this._internal.trySetFinalState(finalState); 33 | } 34 | 35 | public setResult(result: T): void { 36 | this.setFinalState(FinalState.ranToCompletion(result)); 37 | } 38 | public setFaulted(error: Error): void { 39 | this.setFinalState(FinalState.faulted(error)); 40 | } 41 | public setCanceled(): void { 42 | this.setFinalState(FinalState.canceled()); 43 | } 44 | 45 | public trySetResult(result: T): boolean { 46 | return this.trySetFinalState(FinalState.ranToCompletion(result)); 47 | } 48 | public trySetFaulted(error: Error): boolean { 49 | return this.trySetFinalState(FinalState.faulted(error)); 50 | } 51 | public trySetCanceled(): boolean { 52 | return this.trySetFinalState(FinalState.canceled()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/promises/PromiseSpy.ts: -------------------------------------------------------------------------------- 1 | import { PromiseStatus } from './PromiseStatus'; 2 | 3 | export interface PromiseSpy { 4 | readonly promise: Promise; 5 | readonly status: PromiseStatus; 6 | readonly result: T | undefined; 7 | readonly error: Error | undefined; 8 | } 9 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/promises/PromiseSpyImpl.ts: -------------------------------------------------------------------------------- 1 | import { OperationCanceledError } from '../errors'; 2 | import { PromiseSpy } from './PromiseSpy'; 3 | import { PromiseStatus } from './PromiseStatus'; 4 | 5 | /* @internal */ 6 | export class PromiseSpyImpl implements PromiseSpy { 7 | constructor(public readonly promise: Promise) { 8 | promise.then(this.resolveHandler, this.rejectHandler); 9 | } 10 | 11 | public status: PromiseStatus = PromiseStatus.Running; 12 | public result: T | undefined; 13 | public error: Error | undefined; 14 | 15 | private readonly resolveHandler = (result: T): void => { 16 | this.status = PromiseStatus.Succeeded; 17 | this.result = result; 18 | }; 19 | private readonly rejectHandler = (error: Error): void => { 20 | if (error instanceof OperationCanceledError) { 21 | this.status = PromiseStatus.Canceled; 22 | } else { 23 | this.status = PromiseStatus.Faulted; 24 | } 25 | this.error = error; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/promises/PromiseStatus.ts: -------------------------------------------------------------------------------- 1 | export enum PromiseStatus { 2 | Running, 3 | Succeeded, 4 | Faulted, 5 | Canceled, 6 | } 7 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/promises/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FinalState'; 2 | export * from './PromisePal'; 3 | export * from './PromiseCompletionSource'; 4 | export * from './PromiseCompletionSourceInternal'; 5 | export * from './PromiseSpy'; 6 | export * from './PromiseSpyImpl'; 7 | export * from './PromiseStatus'; 8 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/reflection/Constructor/ParameterlessPublic.ts: -------------------------------------------------------------------------------- 1 | export interface ParameterlessPublicCtor { 2 | new (): T; 3 | } 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/reflection/Constructor/PublicCtor.ts: -------------------------------------------------------------------------------- 1 | export interface PublicCtor { 2 | readonly name: string; 3 | readonly prototype: any; 4 | 5 | new (...args: any[]): T; 6 | } 7 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/reflection/Constructor/UnnamedPublicCtor.ts: -------------------------------------------------------------------------------- 1 | export interface UnnamedPublicCtor { 2 | new (...args: any[]): T; 3 | } 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/reflection/Constructor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './PublicCtor'; 2 | export * from './UnnamedPublicCtor'; 3 | export * from './ParameterlessPublic'; 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/reflection/ObjectPal.ts: -------------------------------------------------------------------------------- 1 | import { UnnamedPublicCtor } from './Constructor'; 2 | 3 | export class ObjectPal { 4 | public static become(obj: any, type: UnnamedPublicCtor): T { 5 | const me = obj as Becomable; 6 | me.__proto__ = type.prototype; 7 | me.constructor = type; 8 | return obj; 9 | } 10 | } 11 | 12 | interface Becomable { 13 | __proto__: any; 14 | constructor: new (...args: any[]) => T; 15 | } 16 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/reflection/Type/ExtendedType.ts: -------------------------------------------------------------------------------- 1 | import { PrimitiveTypeName } from './PrimitiveTypeName'; 2 | 3 | /* @internal */ 4 | // tslint:disable-next-line: ban-types 5 | export type ExtendedType = PrimitiveTypeName | Function; 6 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/reflection/Type/Primitive.ts: -------------------------------------------------------------------------------- 1 | export enum Primitive { 2 | string = 'string', 3 | number = 'number', 4 | bigint = 'bigint', 5 | boolean = 'boolean', 6 | void = 'undefined', 7 | } 8 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/reflection/Type/PrimitiveDefinedNonObjectTypeName.ts: -------------------------------------------------------------------------------- 1 | /* @internal */ 2 | export type PrimitiveDefinedNonObjectTypeName = 3 | | 'string' 4 | | 'number' 5 | | 'bigint' 6 | | 'boolean' 7 | | 'symbol' 8 | | 'function'; 9 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/reflection/Type/PrimitiveDefinedTypeName.ts: -------------------------------------------------------------------------------- 1 | import { PrimitiveDefinedNonObjectTypeName } from './PrimitiveDefinedNonObjectTypeName'; 2 | 3 | /* @internal */ 4 | export type PrimitiveDefinedTypeName = PrimitiveDefinedNonObjectTypeName | 'object'; 5 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/reflection/Type/PrimitiveTypeName.ts: -------------------------------------------------------------------------------- 1 | import { PrimitiveDefinedTypeName } from './PrimitiveDefinedTypeName'; 2 | 3 | /* @internal */ 4 | export type PrimitiveTypeName = PrimitiveDefinedTypeName | 'undefined'; 5 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/reflection/Type/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ExtendedType'; 2 | export * from './Primitive'; 3 | export * from './PrimitiveDefinedNonObjectTypeName'; 4 | export * from './PrimitiveDefinedTypeName'; 5 | export * from './PrimitiveTypeName'; 6 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/reflection/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Type'; 2 | export * from './Constructor'; 3 | export * from './ObjectPal'; 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/serialization/JsonConvert.ts: -------------------------------------------------------------------------------- 1 | import { ObjectPal } from '..'; 2 | 3 | /* @internal */ 4 | export class JsonConvert { 5 | public static deserializeObject( 6 | json: string, 7 | type: new (...args: any[]) => T, 8 | ): T { 9 | const result = JSON.parse(json) as T; 10 | return ObjectPal.become(result, type); 11 | } 12 | 13 | public static serializeObject(obj: T): string { 14 | return JSON.stringify(obj); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/serialization/index.ts: -------------------------------------------------------------------------------- 1 | export * from './JsonConvert'; 2 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/synchronization/AsyncAutoResetEvent.ts: -------------------------------------------------------------------------------- 1 | import { 2 | assertArgument, 3 | PromiseCompletionSource, 4 | CancellationToken, 5 | CancellationTokenRegistration, 6 | } from '../..'; 7 | 8 | export class AsyncAutoResetEvent { 9 | private _signalled = false; 10 | private _awaiters = new Array(); 11 | 12 | constructor(initialState: boolean = false) { 13 | assertArgument({ initialState }, 'boolean'); 14 | this._signalled = initialState; 15 | } 16 | 17 | public set(): void { 18 | const _ = this._awaiters.pop()?.signal() ?? (this._signalled = true); 19 | } 20 | 21 | public async waitOne(ct: CancellationToken = CancellationToken.none): Promise { 22 | if (this._signalled) { 23 | this._signalled = false; 24 | 25 | return; 26 | } 27 | 28 | const awaiter = new Awaiter(ct); 29 | this._awaiters.splice(0, 0, awaiter); 30 | 31 | return awaiter.promise; 32 | } 33 | } 34 | 35 | class Awaiter { 36 | constructor(ct: CancellationToken) { 37 | if (ct.canBeCanceled) { 38 | this._ctreg = ct.register(this.cancel); 39 | } 40 | } 41 | 42 | public get promise(): Promise { 43 | return this._pcs.promise; 44 | } 45 | 46 | public signal(): Awaiter { 47 | this._pcs.trySetResult(); 48 | if (this._ctreg) { 49 | this._ctreg.dispose(); 50 | } 51 | return this; 52 | } 53 | 54 | private cancel = () => this._pcs.trySetCanceled(); 55 | 56 | private readonly _pcs = new PromiseCompletionSource(); 57 | 58 | private readonly _ctreg: CancellationTokenRegistration | undefined; 59 | } 60 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/synchronization/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AsyncAutoResetEvent'; 2 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/system/IPlatform.ts: -------------------------------------------------------------------------------- 1 | export interface IPlatform { 2 | readonly id: TId; 3 | 4 | getFullPipeName(shortName: string): string; 5 | pipeExists(shortName: string): Promise; 6 | } 7 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/system/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IPlatform'; 2 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/time/Timeout.ts: -------------------------------------------------------------------------------- 1 | import { TimeSpan } from '.'; 2 | 3 | export class Timeout { 4 | public static readonly infiniteTimeSpan = TimeSpan.fromMilliseconds(-1); 5 | } 6 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/bcl/time/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TimeSpan'; 2 | export * from './Timeout'; 3 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Addresses/Address.ts: -------------------------------------------------------------------------------- 1 | import { CancellationToken, Socket, TimeSpan } from '../../bcl'; 2 | import { ConnectHelper } from '..'; 3 | 4 | export abstract class Address { 5 | /* @internal */ 6 | public abstract get key(): string; 7 | 8 | /* @internal */ 9 | public abstract connect(helper: ConnectHelper, timeout: TimeSpan, ct: CancellationToken): Promise; 10 | } 11 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Addresses/AddressBuilder.ts: -------------------------------------------------------------------------------- 1 | import { Address } from '.'; 2 | 3 | export abstract class AddressBuilder { 4 | /* @internal */ 5 | public abstract assertAddress(): Address; 6 | 7 | protected _address: TAddress | undefined; 8 | } 9 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Addresses/AddressSelectionDelegate.ts: -------------------------------------------------------------------------------- 1 | export interface AddressSelectionDelegate { 2 | (addressBuilder: TAddressFactory): void; 3 | } 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Addresses/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Address'; 2 | export * from './AddressBuilder'; 3 | export * from './AddressSelectionDelegate'; 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Annotations/OperationAnnotations.ts: -------------------------------------------------------------------------------- 1 | import { Primitive, PublicCtor } from '../..'; 2 | 3 | export interface OperationAnnotations { 4 | (target: any, propertyKey: string): void; 5 | (args: { name?: string; returnsPromiseOf?: PublicCtor | Primitive }): ( 6 | target: any, 7 | propertyKey: string, 8 | ) => void; 9 | } 10 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Annotations/OperationAnnotationsWrapper.ts: -------------------------------------------------------------------------------- 1 | import { PublicCtor, Primitive, InvalidOperationError } from '../..'; 2 | import { IServiceProvider } from '..'; 3 | import { OperationAnnotations } from '.'; 4 | 5 | /* @internal */ 6 | export class OperationAnnotationsWrapper { 7 | public constructor(private readonly _domain: IServiceProvider) {} 8 | 9 | public readonly iface: OperationAnnotations = (( 10 | arg0: 11 | | any 12 | | { name?: string; returnsPromiseOf?: PublicCtor | Primitive }, 13 | propertyKey?: string, 14 | ): void | ((target: any, propertyKey: string) => void) => { 15 | if (typeof propertyKey === 'string') { 16 | const _ = this._domain.contractStore 17 | .getOrCreate(arg0.constructor) 18 | .operations.getOrCreate(propertyKey); 19 | return; 20 | } 21 | 22 | // tslint:disable-next-line: no-shadowed-variable 23 | return (target: any, propertyKey: string): void => { 24 | const operationInfo = this._domain.contractStore 25 | .getOrCreate(target.constructor) 26 | .operations.getOrCreate(propertyKey); 27 | 28 | if (!operationInfo) { 29 | throw new InvalidOperationError(); 30 | } 31 | 32 | if (typeof arg0.name === 'string') { 33 | operationInfo.operationName = arg0.name; 34 | } 35 | if (arg0.returnsPromiseOf != null) { 36 | operationInfo.returnsPromiseOf = arg0.returnsPromiseOf; 37 | } 38 | }; 39 | }) as any; 40 | } 41 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Annotations/ServiceAnnotations.ts: -------------------------------------------------------------------------------- 1 | import { PublicCtor } from '../..'; 2 | 3 | export interface ServiceAnnotations { 4 | (target: PublicCtor): any; 5 | (args: { endpoint?: string }): any; 6 | } 7 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Annotations/ServiceAnnotationsWrapper.ts: -------------------------------------------------------------------------------- 1 | // tslint:disable: no-namespace 2 | import { PublicCtor } from '../..'; 3 | import { IServiceProvider } from '..'; 4 | import { ServiceAnnotations } from '.'; 5 | 6 | /* @internal */ 7 | export class ServiceAnnotationsWrapper { 8 | public constructor(private readonly _domain: IServiceProvider) {} 9 | 10 | public readonly iface: ServiceAnnotations = (( 11 | arg0: PublicCtor | { endpoint?: string }, 12 | ): void | ((ctor: PublicCtor) => void) => { 13 | if (typeof arg0 === 'function') { 14 | const _ = this._domain.contractStore.getOrCreate(arg0); 15 | return; 16 | } 17 | 18 | if (arg0 instanceof Object) { 19 | return (ctor: PublicCtor): void => { 20 | const serviceDescriptor = 21 | this._domain.contractStore.getOrCreate(ctor); 22 | 23 | if (arg0.endpoint) { 24 | serviceDescriptor.endpoint = arg0.endpoint; 25 | } 26 | }; 27 | } 28 | 29 | return; 30 | }) as any; 31 | } 32 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Annotations/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ServiceAnnotations'; 2 | export * from './OperationAnnotations'; 3 | 4 | export * from './ServiceAnnotationsWrapper'; 5 | export * from './OperationAnnotationsWrapper'; 6 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Callbacks/Callback.ts: -------------------------------------------------------------------------------- 1 | import { PublicCtor } from '../..'; 2 | import { AddressBuilder, AddressSelectionDelegate } from '../Addresses'; 3 | 4 | export interface Callback { 5 | forAddress(configure: AddressSelectionDelegate): CallbackForAddress; 6 | } 7 | 8 | export interface CallbackForAddress { 9 | forService(callbackService: PublicCtor): CallbackForAddressService; 10 | forService(callbackEndpointName: string): CallbackForAddressService; 11 | } 12 | 13 | export interface CallbackForAddressService { 14 | is(instance: TService): void; 15 | } 16 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Callbacks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Callback'; 2 | export * from './CallbackImpl'; 3 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Configuration/ConnectContext.ts: -------------------------------------------------------------------------------- 1 | import { CancellationToken, TimeSpan } from '../..'; 2 | import { Address } from '..'; 3 | 4 | export interface ConnectContext { 5 | readonly address: TAddress; 6 | readonly timeout: TimeSpan; 7 | readonly ct: CancellationToken; 8 | readonly tryConnectAsync: () => Promise; 9 | } 10 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Configuration/ConnectHelper.ts: -------------------------------------------------------------------------------- 1 | import { Address } from '..'; 2 | import { ConnectContext } from '.'; 3 | 4 | export type ConnectHelper = (context: ConnectContext) => Promise; 5 | 6 | /* @internal */ 7 | export const defaultConnectHelper: ConnectHelper
= async (context: ConnectContext
): Promise => { 8 | await context.tryConnectAsync(); 9 | }; 10 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Configuration/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ConfigStore'; 2 | export * from './ConnectContext'; 3 | export * from './ConnectHelper'; 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Contract/ContractStore.ts: -------------------------------------------------------------------------------- 1 | import { PublicCtor } from '../..'; 2 | import { IContractStore } from './IContractStore'; 3 | import { ServiceDescriptor, ServiceDescriptorImpl } from '.'; 4 | 5 | /* @internal */ 6 | export class ContractStore implements IContractStore { 7 | getOrCreate($class: PublicCtor): ServiceDescriptor { 8 | return this._map.get($class) ?? this.add($class); 9 | } 10 | 11 | maybeGet($class: PublicCtor): ServiceDescriptor | undefined { 12 | return this._map.get($class); 13 | } 14 | 15 | private add($class: PublicCtor): ServiceDescriptor { 16 | const descriptor = new ServiceDescriptorImpl($class); 17 | this._map.set($class, descriptor); 18 | return descriptor; 19 | } 20 | 21 | private readonly _map = new Map>(); 22 | } 23 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Contract/IContractStore.ts: -------------------------------------------------------------------------------- 1 | import { PublicCtor } from '../..'; 2 | import { ServiceDescriptor } from './ServiceDescriptor'; 3 | 4 | /* @internal */ 5 | export interface IContractStore { 6 | getOrCreate($class: PublicCtor): ServiceDescriptor; 7 | 8 | maybeGet($class: PublicCtor): ServiceDescriptor | undefined; 9 | } 10 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Contract/Message.ts: -------------------------------------------------------------------------------- 1 | import { TimeSpan } from '../../bcl'; 2 | 3 | export class Message { 4 | constructor(args?: { payload?: T; requestTimeout?: TimeSpan }) { 5 | this.Payload = args?.payload; 6 | this.RequestTimeout = args?.requestTimeout ?? null; 7 | } 8 | 9 | public readonly Payload?: T; 10 | public RequestTimeout: TimeSpan | null; 11 | } 12 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Contract/OperationDescriptor.ts: -------------------------------------------------------------------------------- 1 | import { Primitive, PublicCtor } from '../..'; 2 | 3 | /* @internal */ 4 | export type OperationDescriptor = { 5 | operationName: string; 6 | 7 | readonly methodName: string; 8 | readonly hasEndingCancellationToken: boolean; 9 | readonly returnType: PublicCtor; 10 | readonly parameterTypes: readonly PublicCtor[]; 11 | returnsPromiseOf?: PublicCtor | Primitive; 12 | }; 13 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Contract/OperationDescriptorImpl.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { PublicCtor, Primitive, CancellationToken } from '../..'; 3 | import { OperationDescriptor, ServiceDescriptorImpl } from '.'; 4 | 5 | /* @internal */ 6 | export class OperationDescriptorImpl implements OperationDescriptor { 7 | constructor( 8 | private readonly _service: ServiceDescriptorImpl, 9 | private readonly _methodName: string, 10 | ) {} 11 | 12 | get methodName(): string { 13 | return this._methodName; 14 | } 15 | 16 | get operationName(): string { 17 | return this._operationName ?? this.methodName; 18 | } 19 | set operationName(value: string) { 20 | this._operationName = value; 21 | } 22 | 23 | public get hasEndingCancellationToken(): boolean { 24 | const parameterTypes = this.parameterTypes; 25 | 26 | return ( 27 | parameterTypes && 28 | parameterTypes.length > 0 && 29 | parameterTypes[parameterTypes.length - 1] === (CancellationToken as any) 30 | ); 31 | } 32 | public get returnType(): PublicCtor { 33 | return Reflect.getMetadata( 34 | 'design:returntype', 35 | this._service.$class.prototype, 36 | this.methodName, 37 | ); 38 | } 39 | public get parameterTypes(): readonly PublicCtor[] { 40 | return Reflect.getMetadata( 41 | 'design:paramtypes', 42 | this._service.$class.prototype, 43 | this.methodName, 44 | ); 45 | } 46 | public returnsPromiseOf?: PublicCtor | Primitive; 47 | 48 | private _operationName: string | undefined; 49 | } 50 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Contract/OperationDescriptorTable.ts: -------------------------------------------------------------------------------- 1 | import { OperationDescriptor } from '.'; 2 | 3 | /* @internal */ 4 | export type OperationDescriptorTable = { 5 | getOrCreate(method: keyof TService & string): OperationDescriptor; 6 | maybeGet(method: keyof TService & string): OperationDescriptor | undefined; 7 | 8 | readonly all: Iterable; 9 | }; 10 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Contract/ServiceDescriptor.ts: -------------------------------------------------------------------------------- 1 | import { OperationDescriptorTable } from '.'; 2 | 3 | /* @internal */ 4 | export type ServiceDescriptor = { 5 | endpoint: string; 6 | readonly operations: OperationDescriptorTable; 7 | }; 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Contract/ServiceDescriptorImpl.ts: -------------------------------------------------------------------------------- 1 | import { PublicCtor } from '../..'; 2 | 3 | import { 4 | OperationDescriptorTable, 5 | ServiceDescriptor, 6 | OperationDescriptor, 7 | OperationDescriptorImpl, 8 | } from '.'; 9 | 10 | type Map = { 11 | [methodName in keyof TService & string]: OperationDescriptorImpl; 12 | }; 13 | 14 | /* @internal */ 15 | export class ServiceDescriptorImpl 16 | implements ServiceDescriptor, OperationDescriptorTable 17 | { 18 | constructor(public readonly $class: PublicCtor) {} 19 | 20 | // #region OperationDescriptorTable 21 | 22 | getOrCreate(method: keyof TService & string): OperationDescriptor { 23 | return ( 24 | this._operations[method] ?? 25 | (this._operations[method] = new OperationDescriptorImpl(this, method)) 26 | ); 27 | } 28 | maybeGet(method: keyof TService & string): OperationDescriptor | undefined { 29 | return this._operations[method]; 30 | } 31 | get all(): Iterable { 32 | return Object.values(this._operations); 33 | } 34 | 35 | // #endregion OperationDescriptorTable 36 | 37 | // #region ServiceDescriptor 38 | 39 | get endpoint(): string { 40 | return this._endpointOverride ?? this.$class.name; 41 | } 42 | set endpoint(value: string) { 43 | this._endpointOverride = value; 44 | } 45 | get operations(): OperationDescriptorTable { 46 | return this; 47 | } 48 | 49 | // #endregion ServiceDescription 50 | 51 | private _endpointOverride: string | undefined; 52 | private _operations: Map = {} as any; 53 | } 54 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Contract/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Message'; 2 | export * from './IContractStore'; 3 | export * from './ContractStore'; 4 | export * from './ServiceDescriptor'; 5 | export * from './ServiceDescriptorImpl'; 6 | export * from './OperationDescriptorTable'; 7 | export * from './OperationDescriptor'; 8 | export * from './OperationDescriptorImpl'; 9 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/IServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ConfigStore, 3 | IContractStore, 4 | DispatchProxyClassStore, 5 | CallbackStoreImpl, 6 | Wire, 7 | ProxySource, 8 | AddressBuilder, 9 | AddressSelectionDelegate, 10 | Address, 11 | } from '.'; 12 | 13 | /* @internal */ 14 | export interface IServiceProvider { 15 | readonly configStore: ConfigStore; 16 | readonly proxySource: ProxySource; 17 | readonly dispatchProxies: DispatchProxyClassStore; 18 | readonly wire: Wire; 19 | readonly contractStore: IContractStore; 20 | readonly callbackStore: CallbackStoreImpl; 21 | 22 | getAddress(configure: AddressSelectionDelegate): Address; 23 | } 24 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/Errors/IpcError.ts: -------------------------------------------------------------------------------- 1 | export class IpcError { 2 | public constructor( 3 | public readonly Message: string, 4 | public readonly StackTrace: string, 5 | public readonly Type: string, 6 | public readonly InnerError: IpcError | null, 7 | ) {} 8 | } 9 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/Errors/RemoteError.ts: -------------------------------------------------------------------------------- 1 | export class RemoteError extends Error { 2 | constructor( 3 | public readonly endpoint: string, 4 | public readonly methodName: string, 5 | inner: Exception, 6 | ) { 7 | super(`${endpoint}.${methodName} threw ${inner.message}.`); 8 | this.name = inner.type; 9 | this.inner = inner.inner; 10 | } 11 | 12 | public inner: Exception | undefined; 13 | } 14 | 15 | export interface Exception { 16 | readonly type: string; 17 | readonly message: string; 18 | readonly stackTrace: string; 19 | readonly inner?: Exception; 20 | } 21 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/Errors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RemoteError'; 2 | export * from './IpcError'; 3 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/Network/IMessageStream.ts: -------------------------------------------------------------------------------- 1 | import { Observer } from 'rxjs'; 2 | import { IAsyncDisposable, CancellationToken, Stream } from '../../../bcl'; 3 | import { Network } from '.'; 4 | 5 | /* @internal */ 6 | export interface IMessageStream extends IAsyncDisposable { 7 | writeMessageAsync(message: Network.Message, ct: CancellationToken): Promise; 8 | } 9 | 10 | /* @internal */ 11 | export module IMessageStream { 12 | export interface Factory { 13 | create(stream: Stream, observer: Observer): IMessageStream; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/Network/Network.ts: -------------------------------------------------------------------------------- 1 | export module Network { 2 | export interface Message { 3 | readonly type: Message.Type; 4 | readonly data: Buffer; 5 | } 6 | 7 | export module Message { 8 | export enum Type { 9 | Request = 0, 10 | Response = 1, 11 | Cancel = 2, 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/Network/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Network'; 2 | export * from './IMessageStream'; 3 | export * from './MessageStream'; 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/Rpc/IRpcChannel.ts: -------------------------------------------------------------------------------- 1 | import { Observer } from 'rxjs'; 2 | import { CancellationToken, TimeSpan, IAsyncDisposable } from '../../../bcl'; 3 | import { ConnectHelper, Address } from '../..'; 4 | import { IMessageStream } from '..'; 5 | import { RpcMessage, RpcCallContext } from '.'; 6 | 7 | /* @internal */ 8 | export interface IRpcChannel extends IAsyncDisposable { 9 | readonly isDisposed: boolean; 10 | call( 11 | request: RpcMessage.Request, 12 | timeout: TimeSpan, 13 | ct: CancellationToken, 14 | ): Promise; 15 | } 16 | 17 | export module IRpcChannel { 18 | /* @internal */ 19 | export interface Factory { 20 | create( 21 | address: TAddress, 22 | connectHelper: ConnectHelper, 23 | connectTimeout: TimeSpan, 24 | ct: CancellationToken, 25 | observer: Observer, 26 | messageStreamFactory?: IMessageStream.Factory, 27 | ): IRpcChannel; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/Rpc/IRpcChannelFactory.ts: -------------------------------------------------------------------------------- 1 | import { Observer } from 'rxjs'; 2 | import { CancellationToken, TimeSpan } from '../../../bcl'; 3 | import { Address, ConnectHelper } from '../..'; 4 | import { IMessageStream } from '..'; 5 | import { IRpcChannel, RpcCallContext } from '.'; 6 | 7 | /* @internal */ 8 | export interface IRpcChannelFactory { 9 | create( 10 | address: Address, 11 | connectHelper: ConnectHelper, 12 | connectTimeout: TimeSpan, 13 | ct: CancellationToken, 14 | observer: Observer, 15 | messageStreamFactory?: IMessageStream.Factory, 16 | ): IRpcChannel; 17 | } 18 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/Rpc/IncommingInitiatingRpcMessage.ts: -------------------------------------------------------------------------------- 1 | import { RpcMessage } from '.'; 2 | 3 | /* @internal */ 4 | export type IncommingInitiatingRpcMessage = RpcMessage.Request | RpcMessage.CancellationRequest; 5 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/Rpc/RpcCallContext.ts: -------------------------------------------------------------------------------- 1 | import { PromiseCompletionSource, CancellationToken, TimeSpan } from '../../../bcl'; 2 | 3 | import { RpcMessage } from '.'; 4 | 5 | /* @internal */ 6 | export type RpcCallContext = RpcCallContext.Incomming | RpcCallContext.Outgoing; 7 | 8 | /* @internal */ 9 | export module RpcCallContext { 10 | export class Incomming { 11 | constructor( 12 | public readonly request: RpcMessage.Request, 13 | public readonly respond: (response: RpcMessage.Response) => Promise, 14 | ) {} 15 | } 16 | 17 | export class Outgoing { 18 | private readonly _pcs = new PromiseCompletionSource(); 19 | 20 | constructor(timeout: TimeSpan, ct: CancellationToken) { 21 | timeout.bind(this._pcs); 22 | ct.bind(this._pcs); 23 | } 24 | 25 | public get promise(): Promise { 26 | return this._pcs.promise; 27 | } 28 | 29 | public complete(response: RpcMessage.Response): void { 30 | const _ = this._pcs.trySetResult(response); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/Rpc/RpcMessageBase.ts: -------------------------------------------------------------------------------- 1 | import { Network } from '..'; 2 | 3 | /* @internal */ 4 | export abstract class RpcMessageBase { 5 | public abstract toNetwork(): Network.Message; 6 | } 7 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/Rpc/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IRpcChannel'; 2 | export * from './RpcChannel'; 3 | export * from './RpcCallContext'; 4 | export * from './RpcMessageBase'; 5 | export * from './RpcMessage'; 6 | export * from './IncommingInitiatingRpcMessage'; 7 | export * from './IRpcChannelFactory'; 8 | export * from './Converter'; 9 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Protocol/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Network'; 2 | export * from './Errors'; 3 | export * from './Rpc'; 4 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Proxies/CallbackStoreImpl.ts: -------------------------------------------------------------------------------- 1 | import { Address } from '../Addresses'; 2 | 3 | /* @internal */ 4 | export class CallbackStoreImpl { 5 | public get(callbackEndpointName: string, address: Address): any | undefined { 6 | const compositeKey = CallbackStoreImpl.computeCompositeKey(callbackEndpointName, address); 7 | 8 | return this._map.get(compositeKey); 9 | } 10 | 11 | public set(callbackEndpointName: string, address: Address, instance: any): void { 12 | const compositeKey = CallbackStoreImpl.computeCompositeKey(callbackEndpointName, address); 13 | 14 | this._map.set(compositeKey, instance); 15 | } 16 | 17 | private static computeCompositeKey(callbackEndpointName: string, address: Address): string { 18 | return `${callbackEndpointName}@${address.key}`; 19 | } 20 | 21 | private readonly _map = new Map(); 22 | } 23 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Proxies/DispatchProxy/DispatchProxyClass.ts: -------------------------------------------------------------------------------- 1 | import { ICallInterceptor, ICallInterceptorContainer } from '.'; 2 | 3 | /* @internal */ 4 | export type DispatchProxyClass = 5 | new(callInterceptor: ICallInterceptor) 6 | => TService & ICallInterceptorContainer; 7 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Proxies/DispatchProxy/DispatchProxyClassStore.ts: -------------------------------------------------------------------------------- 1 | import { assertArgument, ConditionalWeakTable, PublicCtor } from '../../..'; 2 | import { DispatchProxyClass, Weaver } from '.'; 3 | 4 | /* @internal */ 5 | export class DispatchProxyClassStore { 6 | private readonly _map = new ConditionalWeakTable(); 7 | 8 | public getOrCreate(service: PublicCtor): DispatchProxyClass { 9 | assertArgument({ service }, 'function'); 10 | 11 | return this._map.getOrCreateValue(service, _ => Weaver.weave(service)) as any; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Proxies/DispatchProxy/ICallInterceptor.ts: -------------------------------------------------------------------------------- 1 | /* @internal */ 2 | export interface ICallInterceptor { 3 | invokeMethod(methodName: string & keyof TService, args: unknown[]): Promise; 4 | } 5 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Proxies/DispatchProxy/ICallInterceptorContainer.ts: -------------------------------------------------------------------------------- 1 | import { ICallInterceptor } from '.'; 2 | 3 | /* @internal */ 4 | export const symbolofCallInterceptor = Symbol('CallInterceptor'); 5 | 6 | /* @internal */ 7 | export interface ICallInterceptorContainer { 8 | [symbolofCallInterceptor]: ICallInterceptor; 9 | } 10 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Proxies/DispatchProxy/MethodNameEnumerator.ts: -------------------------------------------------------------------------------- 1 | import { assertArgument, PublicCtor } from '../../..'; 2 | 3 | /* @internal */ 4 | export class MethodNameEnumerator { 5 | public static enumerate(ctor: PublicCtor): Array { 6 | assertArgument({ ctor }, 'function'); 7 | 8 | const instance = new MethodNameEnumerator(ctor); 9 | instance.run(); 10 | return instance._output; 11 | } 12 | 13 | private constructor(private readonly _ctor: PublicCtor) {} 14 | 15 | private _output: Array = null as any; 16 | 17 | private run(): void { 18 | this._output = Reflect.ownKeys(this._ctor.prototype).filter(this.refersToANamedMethod); 19 | } 20 | 21 | private readonly refersToANamedMethod = ( 22 | key: string | number | symbol, 23 | ): key is string & keyof T => { 24 | return ( 25 | typeof key === 'string' && 26 | typeof this._ctor.prototype[key] === 'function' && 27 | this._ctor !== this._ctor.prototype[key] 28 | ); 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Proxies/DispatchProxy/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Weaver'; 2 | export * from './ICallInterceptor'; 3 | export * from './ICallInterceptorContainer'; 4 | export * from './DispatchProxyClass'; 5 | export * from './MethodNameEnumerator'; 6 | export * from './DispatchProxyClassStore'; 7 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Proxies/ProxyId.ts: -------------------------------------------------------------------------------- 1 | import { PublicCtor } from '../../bcl'; 2 | import { Address } from '..'; 3 | 4 | /* @internal */ 5 | export class ProxyId { 6 | constructor( 7 | public readonly service: PublicCtor, 8 | public readonly address: Address, 9 | ) {} 10 | } 11 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Proxies/ProxySource.ts: -------------------------------------------------------------------------------- 1 | import { ConditionalWeakTable, Dictionary, PublicCtor } from '../../bcl'; 2 | import { Address, AddressBuilder } from '..'; 3 | import { ICallInterceptor, IServiceProvider, ProxyId } from '.'; 4 | 5 | /* @internal */ 6 | export class ProxySource { 7 | private static readonly _serviceToAddressToProxy = new ConditionalWeakTable>(); 8 | 9 | constructor( 10 | private readonly _sp: IServiceProvider, 11 | ) { } 12 | 13 | public resolve(proxyId: ProxyId): TService { 14 | return ProxySource 15 | ._serviceToAddressToProxy 16 | .getOrCreateValue(proxyId.service, Dictionary.create) 17 | .getOrCreateValue(proxyId.address.key, _ => this.createProxy(proxyId)) as TService 18 | ; 19 | } 20 | 21 | private createProxy(proxyId: ProxyId): TService { 22 | const me = this; 23 | 24 | // The following inline class captures the proxyId parameter. 25 | const InterceptorClass = class implements ICallInterceptor 26 | { 27 | invokeMethod(methodName: keyof TService & string, args: unknown[]): Promise { 28 | return me._sp.wire.invokeMethod( 29 | proxyId, 30 | methodName, 31 | args, 32 | ); 33 | } 34 | }; 35 | 36 | const DispatcherProxyClass = this._sp.dispatchProxies.getOrCreate(proxyId.service); 37 | 38 | const proxy = new DispatcherProxyClass(new InterceptorClass()); 39 | 40 | return proxy; 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Proxies/Wire.ts: -------------------------------------------------------------------------------- 1 | import { Address, IMessageStream, IRpcChannelFactory, MessageStream, RpcChannel } from '..'; 2 | import { ChannelManager, IServiceProvider, ProxyId } from '.'; 3 | import { Dictionary } from '../../bcl'; 4 | 5 | /* @internal */ 6 | export class Wire { 7 | invokeMethod(proxyId: ProxyId, methodName: keyof TService & string, args: unknown[]): Promise { 8 | const channelManager = this.getOrCreateChannelManager(proxyId.address); 9 | 10 | return channelManager.invokeMethod(proxyId.service, methodName, args); 11 | } 12 | 13 | constructor( 14 | private readonly _sp: IServiceProvider, 15 | private readonly _rpcChannelFactory: IRpcChannelFactory = RpcChannel, 16 | private readonly _messageStreamFactory: IMessageStream.Factory = new MessageStream.Factory(), 17 | ) { } 18 | 19 | private getOrCreateChannelManager(address: Address): ChannelManager { 20 | return this._map.getOrCreateValue( 21 | address.key, 22 | () => new ChannelManager( 23 | this._sp, 24 | address, 25 | this._rpcChannelFactory, 26 | this._messageStreamFactory)); 27 | } 28 | 29 | private readonly _map = new Dictionary(); 30 | } 31 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/Proxies/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProxySource'; 2 | export * from './ProxyId'; 3 | export * from '../IServiceProvider'; 4 | export * from './DispatchProxy'; 5 | export * from './Wire'; 6 | export * from './ChannelManager'; 7 | export * from './RpcRequestFactory'; 8 | export * from './CallbackStoreImpl'; 9 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/ServiceId.ts: -------------------------------------------------------------------------------- 1 | import { PublicCtor } from '..'; 2 | 3 | export class ServiceId { 4 | public static from(service: PublicCtor) { 5 | return new ServiceId(service); 6 | } 7 | 8 | constructor( 9 | public readonly service: PublicCtor, 10 | public readonly endpointName?: string, 11 | ) {} 12 | 13 | /* @internal */ 14 | public get key() { 15 | return this.endpointName ?? this.service.name; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/core/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Addresses'; 2 | export * from './Configuration'; 3 | export * from './IpcBase'; 4 | export * from './ServiceId'; 5 | export * from './Proxies'; 6 | export * from './Protocol'; 7 | export * from './Contract'; 8 | export * from './Annotations'; 9 | export * from './Callbacks'; 10 | -------------------------------------------------------------------------------- /src/Clients/js/src/std/index.ts: -------------------------------------------------------------------------------- 1 | export * from './bcl'; 2 | export * from './core'; 3 | -------------------------------------------------------------------------------- /src/Clients/js/src/web/Ipc.ts: -------------------------------------------------------------------------------- 1 | import { IpcBaseImpl, AddressSelectionDelegate, IpcBase } from '../std'; 2 | import { WebAddressBuilder } from './WebAddressBuilder'; 3 | 4 | /* @internal */ 5 | export class IpcWebImpl extends IpcBaseImpl implements Ipc { 6 | constructor() { 7 | super(WebAddressBuilder); 8 | } 9 | 10 | public webSocket( 11 | url: string, 12 | ): AddressSelectionDelegate { 13 | return builder => builder.isWebSocket(url); 14 | } 15 | } 16 | 17 | export interface Ipc extends IpcBase { 18 | webSocket(url: string): AddressSelectionDelegate; 19 | } 20 | 21 | export const ipc: Ipc = new IpcWebImpl(); 22 | -------------------------------------------------------------------------------- /src/Clients/js/src/web/Platform.ts: -------------------------------------------------------------------------------- 1 | import { 2 | InvalidOperationError, 3 | PlatformNotSupportedError, 4 | IPlatform, 5 | } from '../std'; 6 | 7 | /* @internal */ 8 | export module Platform { 9 | export enum Id { 10 | Web, 11 | } 12 | 13 | class Web implements IPlatform { 14 | get id(): Id { 15 | return Id.Web; 16 | } 17 | 18 | getFullPipeName(shortName: string): string { 19 | throw new PlatformNotSupportedError(); 20 | } 21 | 22 | async pipeExists(shortName: string): Promise { 23 | throw new PlatformNotSupportedError(); 24 | } 25 | } 26 | 27 | function detect(): Id { 28 | return Id.Web; 29 | } 30 | 31 | function create(): IPlatform { 32 | switch (detect()) { 33 | case Id.Web: 34 | return new Web(); 35 | default: 36 | throw new InvalidOperationError(); 37 | } 38 | } 39 | 40 | export const current = create(); 41 | } 42 | -------------------------------------------------------------------------------- /src/Clients/js/src/web/Transport/WebSockets/BrowserWebSocketAddress.ts: -------------------------------------------------------------------------------- 1 | import { TimeSpan, CancellationToken, Socket, ConnectHelper, Address } from '../../../std'; 2 | import { BrowserWebSocket } from './BrowserWebSocket'; 3 | 4 | export class BrowserWebSocketAddress extends Address { 5 | constructor(public readonly url: string) { 6 | super(); 7 | } 8 | 9 | public override get key() { 10 | return `websocket:${this.url}`; 11 | } 12 | 13 | public override async connect(helper: ConnectHelper, timeout: TimeSpan, ct: CancellationToken): Promise { 14 | return await BrowserWebSocket.connectWithHelper(helper, this.url, timeout, ct); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Clients/js/src/web/Transport/WebSockets/BrowserWebSocketError.ts: -------------------------------------------------------------------------------- 1 | import { CoreIpcError } from '../../../std'; 2 | import { BrowserWebSocketLike } from './BrowserWebSocketLike'; 3 | 4 | export class BrowserWebSocketError extends CoreIpcError {} 5 | 6 | export module BrowserWebSocketError { 7 | export class ConnectFailure extends BrowserWebSocketError { 8 | /* @internal */ 9 | constructor(public readonly socket: BrowserWebSocketLike, message?: string) { 10 | super(message ?? ConnectFailure.defaultMessage); 11 | } 12 | 13 | private static readonly defaultMessage = 14 | 'Received an error while awaiting for a WebSocket to connect.'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Clients/js/src/web/Transport/WebSockets/BrowserWebSocketLike.ts: -------------------------------------------------------------------------------- 1 | export interface BrowserWebSocketLike { 2 | binaryType: 'blob' | 'arraybuffer'; 3 | 4 | send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void; 5 | close(code?: number, reason?: string): void; 6 | 7 | onopen: ((this: WebSocket, ev: Event) => any) | null; 8 | onclose: ((this: WebSocket, ev: CloseEvent) => any) | null; 9 | onerror: ((this: WebSocket, ev: Event) => any) | null; 10 | onmessage: ((this: WebSocket, ev: MessageEvent) => any) | null; 11 | } 12 | -------------------------------------------------------------------------------- /src/Clients/js/src/web/Transport/WebSockets/BrowserWebSocketLikeCtor.ts: -------------------------------------------------------------------------------- 1 | import { BrowserWebSocketLike } from '.'; 2 | 3 | /* @internal */ 4 | export type BrowserWebSocketLikeCtor = new ( 5 | url: string | URL, 6 | protocols?: string | string[], 7 | ) => BrowserWebSocketLike; 8 | -------------------------------------------------------------------------------- /src/Clients/js/src/web/Transport/WebSockets/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BrowserWebSocket'; 2 | export * from './BrowserWebSocketAddress'; 3 | export * from './BrowserWebSocketLike'; 4 | export * from './BrowserWebSocketLikeCtor'; 5 | export * from './BrowserWebSocketError'; 6 | -------------------------------------------------------------------------------- /src/Clients/js/src/web/Transport/index.ts: -------------------------------------------------------------------------------- 1 | export * from './WebSockets'; 2 | -------------------------------------------------------------------------------- /src/Clients/js/src/web/WebAddressBuilder.ts: -------------------------------------------------------------------------------- 1 | import { AddressBuilder, PublicCtor } from '../std'; 2 | import { BrowserWebSocketAddress } from './Transport'; 3 | 4 | export class WebAddressBuilder extends AddressBuilder { 5 | /* @internal */ 6 | public assertAddress(): BrowserWebSocketAddress { 7 | if (this._address instanceof BrowserWebSocketAddress) { 8 | return this._address; 9 | } 10 | 11 | throw new Error('Method isWebSocket was not called in the address callback.'); 12 | } 13 | 14 | public isWebSocket(url: string): PublicCtor { 15 | this._address = new BrowserWebSocketAddress(url); 16 | return BrowserWebSocketAddress; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Clients/js/src/web/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Platform'; 2 | export * from './Transport'; 3 | export * from './Ipc'; 4 | export * from '../std'; 5 | export * from './WebAddressBuilder'; 6 | -------------------------------------------------------------------------------- /src/Clients/js/test/dotnet/CoreIpcServer/InteropAddress.ts: -------------------------------------------------------------------------------- 1 | import { Address, assertArgument } from '../../../src/std'; 2 | import { NamedPipeAddress } from '../../../src/node'; 3 | import { BrowserWebSocketAddress } from '../../../src/web'; 4 | 5 | export abstract class InteropAddress { 6 | public static from(address: Address): InteropAddress { 7 | switch ( 8 | assertArgument({ address }, BrowserWebSocketAddress, NamedPipeAddress) 9 | ) { 10 | case BrowserWebSocketAddress: { 11 | return new InteropAddress.WebSocket( 12 | address as BrowserWebSocketAddress 13 | ); 14 | } 15 | case NamedPipeAddress: { 16 | return new InteropAddress.NamedPipe( 17 | address as NamedPipeAddress 18 | ); 19 | } 20 | default: { 21 | throw void 0; 22 | } 23 | } 24 | } 25 | 26 | public static computeCommandLineArgs(interopAddresses: InteropAddress[]): string[] { return interopAddresses.flatMap(x => x.commandLineArgs()); } 27 | 28 | public abstract commandLineArgs(): string[]; 29 | } 30 | 31 | export module InteropAddress { 32 | export class WebSocket extends InteropAddress { 33 | constructor(private readonly _underlyingAddress: BrowserWebSocketAddress) { super(); } 34 | 35 | public override commandLineArgs() { return ['--websocket', this._underlyingAddress.url]; } 36 | } 37 | 38 | export class NamedPipe extends InteropAddress { 39 | constructor(private readonly _underlyingAddress: NamedPipeAddress) { super(); } 40 | 41 | public override commandLineArgs() { return ['--pipe', this._underlyingAddress.name]; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Clients/js/test/dotnet/CoreIpcServer/NonZeroExitError.ts: -------------------------------------------------------------------------------- 1 | import { ChildProcess } from 'child_process'; 2 | import cliColor from 'cli-color'; 3 | 4 | export class NonZeroExitError extends Error { 5 | constructor( 6 | private readonly _process: ChildProcess, 7 | private readonly _stdout: string, 8 | private readonly _stderr: string, 9 | ) { 10 | super(); 11 | } 12 | 13 | public prettyPrint(): void { 14 | console.group( 15 | cliColor.bold.whiteBright(`🛑 Process `), 16 | cliColor.bold.yellowBright(JSON.stringify(this._process.spawnargs)), 17 | cliColor.bold.whiteBright('with PID'), 18 | cliColor.bold.yellowBright(this._process.pid), 19 | cliColor.bold.whiteBright('exited with code'), 20 | cliColor.bold.redBright(this._process.exitCode), 21 | ); 22 | 23 | console.group(cliColor.bold.whiteBright(`🪵 STDOUT`)); 24 | if (this._stdout) { 25 | console.log(this._stdout); 26 | } 27 | console.groupEnd(); 28 | 29 | console.group(cliColor.bold.whiteBright(`🪵 STDERR`)); 30 | if (this._stderr) { 31 | console.log(this._stderr); 32 | } 33 | console.groupEnd(); 34 | 35 | console.groupEnd(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Clients/js/test/dotnet/CoreIpcServer/Paths.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | export class Paths { 4 | public static get absoluteTargetDir(): string { 5 | const relativeTargetDir = 6 | process.env[Paths.NodeJS_NetCoreAppTargetDir_RelativePath] ?? 7 | path.join( 8 | Paths.DotNet, 9 | Paths.UiPath_CoreIpc_NodeInterop, 10 | Paths.Bin, 11 | Paths.Debug, 12 | Paths.Net60 13 | ); 14 | 15 | const absoluteTargetDir = path.join(process.cwd(), relativeTargetDir); 16 | 17 | return absoluteTargetDir; 18 | } 19 | 20 | public static get entryPoint(): string { 21 | return path.join(Paths.absoluteTargetDir, Paths.UiPath_CoreIpc_NodeInterop_dll); 22 | } 23 | 24 | private static get UiPath_CoreIpc_NodeInterop_dll(): string { 25 | return `${Paths.UiPath_CoreIpc_NodeInterop}.dll`; 26 | } 27 | 28 | private static readonly NodeJS_NetCoreAppTargetDir_RelativePath = 'NodeJS_NetCoreAppTargetDir_RelativePath'; 29 | private static readonly UiPath_CoreIpc_NodeInterop = 'UiPath.CoreIpc.NodeInterop'; 30 | private static readonly DotNet = 'dotnet'; 31 | private static readonly Bin = 'bin'; 32 | private static readonly Debug = 'Debug'; 33 | private static readonly Net60 = 'net6.0'; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/Clients/js/test/dotnet/CoreIpcServer/Signal.ts: -------------------------------------------------------------------------------- 1 | export interface Signal { 2 | Kind: Signal.Kind; 3 | Details: TDetails; 4 | } 5 | 6 | export module Signal { 7 | export enum Kind { 8 | Throw = 'Throw', 9 | PoweringOn = 'PoweringOn', 10 | ReadyToConnect = 'ReadyToConnect', 11 | } 12 | export interface ExceptionDetails { 13 | Type: string; 14 | Message: string; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Clients/js/test/dotnet/CoreIpcServer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Paths'; 2 | export * from './DotNetProcess'; 3 | export * from './Signal'; 4 | export * from './CoreIpcServer'; 5 | export * from './InteropAddress'; 6 | export * from './NpmProcess'; 7 | -------------------------------------------------------------------------------- /src/Clients/js/test/infrastructure/__.ts: -------------------------------------------------------------------------------- 1 | const stack = new Array(); 2 | 3 | export function __for(description: string, specDefinitions: () => void): void { 4 | stack.push(description); 5 | 6 | const concatenatedDescription = [...stack, description].join(' '); 7 | 8 | describe(concatenatedDescription, specDefinitions); 9 | 10 | stack.pop(); 11 | } 12 | 13 | export function __fact( 14 | expectation: string, 15 | assertion?: jasmine.ImplementationCallback, 16 | timeout?: number, 17 | ): void { 18 | const concatenatedExpectation = [...stack, expectation].join(' '); 19 | 20 | const newArgs = [...arguments] as Parameters; 21 | newArgs[0] = concatenatedExpectation; 22 | 23 | it(...newArgs); 24 | } 25 | -------------------------------------------------------------------------------- /src/Clients/js/test/infrastructure/__members.ts: -------------------------------------------------------------------------------- 1 | export function __members(type: T): Members { 2 | const staticMethods = Object.getOwnPropertyNames(type).map(x => ({ 3 | [x]: `📞 "${x}" static method`, 4 | })); 5 | const instanceMethods = Object.getOwnPropertyNames(type.prototype).map(x => ({ 6 | [x]: `📞 "${x}" instance method`, 7 | })); 8 | 9 | let result = {}; 10 | 11 | for (const obj of staticMethods) { 12 | result = { ...result, ...obj }; 13 | } 14 | for (const obj of instanceMethods) { 15 | result = { ...result, ...obj }; 16 | } 17 | 18 | return result as any; 19 | } 20 | 21 | export type Members = Members.Instance & Members.Static; 22 | 23 | export module Members { 24 | export type Instance = { 25 | readonly [name in keyof T['prototype']]: keyof T['prototype']; 26 | }; 27 | 28 | export type Static = { 29 | readonly [name in keyof T]: keyof T; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/Clients/js/test/infrastructure/__parameters.ts: -------------------------------------------------------------------------------- 1 | import { ArgumentErrorBase } from '../../src/std'; 2 | 3 | export function __mentionsParameter(name: string) { 4 | return (x: any) => { 5 | expect(x).toBeInstanceOf(ArgumentErrorBase); 6 | 7 | const specific = x as ArgumentErrorBase; 8 | 9 | expect(specific.paramName) 10 | .withContext(`The ${ArgumentErrorBase.name}'s paramName`) 11 | .toBe(name); 12 | 13 | return true; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/Clients/js/test/infrastructure/cover/index.ts: -------------------------------------------------------------------------------- 1 | export { cover, fcover, CoverTypeContext } from './internal'; 2 | -------------------------------------------------------------------------------- /src/Clients/js/test/infrastructure/cover/internal/coverType.ts: -------------------------------------------------------------------------------- 1 | import { PublicCtor } from '../../../../src/std'; 2 | import { CoverTypeContext, CoverTypeContextFactory } from '.'; 3 | 4 | export function cover any>( 5 | type: PublicCtor>, 6 | spec: (this: CoverTypeContext, TStatic>) => void, 7 | ): void { 8 | const context = CoverTypeContextFactory.create, TStatic>(type); 9 | 10 | describe(`🌲 "${type.name}"`, () => { 11 | spec.call(context); 12 | }); 13 | } 14 | 15 | export function fcover any>( 16 | type: PublicCtor>, 17 | spec: (this: CoverTypeContext, TStatic>) => void, 18 | ): void { 19 | const context = CoverTypeContextFactory.create, TStatic>(type); 20 | 21 | fdescribe(`🌲 "${type.name}"`, () => { 22 | spec.call(context); 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /src/Clients/js/test/infrastructure/cover/internal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './coverType'; 2 | export * from './CoverTypeContext'; 3 | -------------------------------------------------------------------------------- /src/Clients/js/test/infrastructure/cover2/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Cover'; 2 | -------------------------------------------------------------------------------- /src/Clients/js/test/infrastructure/overloadedParameters.ts: -------------------------------------------------------------------------------- 1 | export type Overloads any> = 2 | T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; (...args: infer A3): infer R3; (...args: infer A4): infer R4; (...args: infer A5): infer R5; (...args: infer A6): infer R6 } ? 3 | ((...args: A1) => R1) | ((...args: A2) => R2) | ((...args: A3) => R3) | ((...args: A4) => R4) | ((...args: A5) => R5) | ((...args: A6) => R6) 4 | : T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; (...args: infer A3): infer R3; (...args: infer A4): infer R4; (...args: infer A5): infer R5 } ? 5 | ((...args: A1) => R1) | ((...args: A2) => R2) | ((...args: A3) => R3) | ((...args: A4) => R4) | ((...args: A5) => R5) 6 | : T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; (...args: infer A3): infer R3; (...args: infer A4): infer R4 } ? 7 | ((...args: A1) => R1) | ((...args: A2) => R2) | ((...args: A3) => R3) | ((...args: A4) => R4) 8 | : T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; (...args: infer A3): infer R3 } ? 9 | ((...args: A1) => R1) | ((...args: A2) => R2) | ((...args: A3) => R3) 10 | : T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2 } ? 11 | ((...args: A1) => R1) | ((...args: A2) => R2) 12 | : T extends { (...args: infer A1): infer R1 } ? 13 | (...args: A1) => R1 14 | : never 15 | 16 | export type OverloadedParameters any> = Parameters>; 17 | -------------------------------------------------------------------------------- /src/Clients/js/test/node/Contracts/IAlgebra.ts: -------------------------------------------------------------------------------- 1 | import { Message } from '../../../src/std'; 2 | 3 | export class IAlgebra { 4 | public MultiplySimple(x: number, y: number): Promise { 5 | throw void 0; 6 | } 7 | 8 | public Sleep(milliseconds: number): Promise { 9 | throw void 0; 10 | } 11 | 12 | public TestMessage(message: Message): Promise { 13 | throw void 0; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Clients/js/test/node/Contracts/IArithmetic.ts: -------------------------------------------------------------------------------- 1 | import { Message } from '../../../src/std'; 2 | 3 | 4 | export interface IArithmetic { 5 | Sum(x: number, y: number): Promise; 6 | SendMessage(message: Message): Promise; 7 | } 8 | -------------------------------------------------------------------------------- /src/Clients/js/test/node/Contracts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IAlgebra'; 2 | export * from './IArithmetic'; 3 | -------------------------------------------------------------------------------- /src/Clients/js/test/node/Fixtures/index.ts: -------------------------------------------------------------------------------- 1 | import { AddressSelectionDelegate, NodeAddressBuilder } from "../../../src/node"; 2 | 3 | export abstract class AddressHelper { 4 | public abstract get address(): AddressSelectionDelegate; 5 | public toString(): string { return `${this.kind}`; } 6 | 7 | protected abstract get kind(): AddressHelper.Kind; 8 | } 9 | 10 | export module AddressHelper { 11 | export enum Kind { 12 | WebSocket = 'WebSocket', 13 | NamedPipe = 'NamedPipe', 14 | } 15 | 16 | module Impl { 17 | export class WebSocket extends AddressHelper { 18 | public override get address(): AddressSelectionDelegate { return x => x.isWebSocket('ws://127.0.0.1:61234'); } 19 | 20 | protected override get kind(): AddressHelper.Kind { return Kind.WebSocket; } 21 | } 22 | 23 | export class NamedPipe extends AddressHelper { 24 | public override get address(): AddressSelectionDelegate { return x => x.isPipe('uipath-coreipc-test-pipe'); } 25 | 26 | protected override get kind(): AddressHelper.Kind { return Kind.NamedPipe; } 27 | } 28 | } 29 | 30 | export const WebSocket = new Impl.WebSocket(); 31 | export const NamedPipe = new Impl.NamedPipe(); 32 | } 33 | -------------------------------------------------------------------------------- /src/Clients/js/test/node/core/Ipc.test.ts: -------------------------------------------------------------------------------- 1 | import { TimeSpan } from '../../../src/std'; 2 | import { ipc, IpcNodeImpl, NamedPipeAddress } from '../../../src/node'; 3 | 4 | import { expect } from 'chai'; 5 | import { _jsargs } from '../../infrastructure'; 6 | 7 | describe(`ipc`, () => { 8 | class MockContract {} 9 | const mockAddress = new NamedPipeAddress('some-pipe'); 10 | const cMilliseconds = 2000; 11 | 12 | it('should work', () => { 13 | ipc.config.forAnyAddress().forAnyService().setRequestTimeout(cMilliseconds); 14 | const actual = (ipc as IpcNodeImpl).configStore.getRequestTimeout( 15 | mockAddress, 16 | MockContract, 17 | ); 18 | 19 | expect(actual).to.not.be.undefined; 20 | 21 | actual!.should.be 22 | .instanceOf(TimeSpan) 23 | .and.have.property('totalMilliseconds') 24 | .equal(cMilliseconds); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/Clients/js/test/std/bcl/ArgumentError.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, constructing, __fact, __for } from '../../infrastructure'; 2 | import { ArgumentError } from '../../../src/std'; 3 | 4 | __for(`${ArgumentError.name}'s`, () => { 5 | __for(`ctor`, () => { 6 | __fact(`should not throw`, () => { 7 | for (const paramName of paramNames) { 8 | for (const message of messages) { 9 | constructing(ArgumentError, paramName, message).should.not.throw(); 10 | } 11 | } 12 | }); 13 | 14 | __fact(`should set the paramName property accordingly`, () => { 15 | for (const paramName of paramNames) { 16 | for (const message of messages) { 17 | expect(new ArgumentError(message, paramName).paramName).to.be.eq(paramName); 18 | } 19 | } 20 | }); 21 | 22 | __fact(`should set the message property accordingly`, () => { 23 | expect(new ArgumentError().message).to.be.eq( 24 | 'Value does not fall within the expected range.', 25 | ); 26 | expect(new ArgumentError('someMessage').message).to.be.eq(`someMessage`); 27 | expect(new ArgumentError('someMessage', 'someParam').message).to.be.eq( 28 | `someMessage (Parameter: 'someParam')`, 29 | ); 30 | expect(new ArgumentError(undefined, 'someParam').message).to.be.eq( 31 | `Value does not fall within the expected range. (Parameter: 'someParam')`, 32 | ); 33 | }); 34 | 35 | const paramNames = ['someName', null, undefined, ''] as never[]; 36 | const messages = ['some message', null, undefined, ''] as never[]; 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/Clients/js/test/std/bcl/ArgumentNullError.test.ts: -------------------------------------------------------------------------------- 1 | import { constructing, context } from '../../infrastructure'; 2 | import { ArgumentNullError } from '../../../src/std'; 3 | import { expect } from 'chai'; 4 | 5 | describe(`${ArgumentNullError.name}'s`, () => { 6 | context(`ctor`, () => { 7 | it(`should not throw`, () => { 8 | for (const paramName of paramNames) { 9 | for (const message of messages) { 10 | constructing(ArgumentNullError, paramName, message).should.not.throw(); 11 | } 12 | } 13 | }); 14 | 15 | it(`should set the paramName property accordingly`, () => { 16 | for (const paramName of paramNames) { 17 | for (const message of messages) { 18 | expect(new ArgumentNullError(paramName, message).paramName).to.be.eq(paramName); 19 | } 20 | } 21 | }); 22 | 23 | it(`should set the message property accordingly`, () => { 24 | expect(new ArgumentNullError().message).to.be.eq('Value cannot be null.'); 25 | expect(new ArgumentNullError('someParam').message).to.be.eq( 26 | `Value cannot be null. (Parameter: 'someParam')`, 27 | ); 28 | expect(new ArgumentNullError('someParam', 'someMessage').message).to.be.eq( 29 | `someMessage (Parameter: 'someParam')`, 30 | ); 31 | expect(new ArgumentNullError(undefined, 'someMessage').message).to.be.eq(`someMessage`); 32 | }); 33 | 34 | const paramNames = ['someName', null, undefined, ''] as never[]; 35 | const messages = ['some message', null, undefined, ''] as never[]; 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /src/Clients/js/test/std/bcl/ArgumentOutOfRangeError.test.ts: -------------------------------------------------------------------------------- 1 | import { constructing, context } from '../../infrastructure'; 2 | import { ArgumentOutOfRangeError } from '../../../src/std'; 3 | import { expect } from 'chai'; 4 | 5 | describe(`${ArgumentOutOfRangeError.name}'s`, () => { 6 | context(`ctor`, () => { 7 | it(`should not throw`, () => { 8 | for (const paramName of paramNames) { 9 | for (const message of messages) { 10 | constructing(ArgumentOutOfRangeError, paramName, message).should.not.throw(); 11 | } 12 | } 13 | }); 14 | 15 | it(`should set the paramName property accordingly`, () => { 16 | for (const paramName of paramNames) { 17 | for (const message of messages) { 18 | expect(new ArgumentOutOfRangeError(paramName, message).paramName).to.be.eq( 19 | paramName, 20 | ); 21 | } 22 | } 23 | }); 24 | 25 | it(`should set the message property accordingly`, () => { 26 | expect(new ArgumentOutOfRangeError().message).to.be.eq( 27 | 'Specified argument was out of the range of valid values.', 28 | ); 29 | expect(new ArgumentOutOfRangeError('someParam').message).to.be.eq( 30 | `Specified argument was out of the range of valid values. (Parameter: 'someParam')`, 31 | ); 32 | expect(new ArgumentOutOfRangeError('someParam', 'someMessage').message).to.be.eq( 33 | `someMessage (Parameter: 'someParam')`, 34 | ); 35 | expect(new ArgumentOutOfRangeError(undefined, 'someMessage').message).to.be.eq( 36 | `someMessage`, 37 | ); 38 | }); 39 | 40 | const paramNames = ['someName', null, undefined, ''] as never[]; 41 | const messages = ['some message', null, undefined, ''] as never[]; 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/Clients/js/test/std/bcl/AsyncAutoResetEvent.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { AsyncAutoResetEvent, PromisePal, TimeSpan } from '../../../src/std'; 3 | 4 | describe(`${AsyncAutoResetEvent.name}`, function () { 5 | it(`should work`, async () => { 6 | const x = new AsyncAutoResetEvent(); 7 | 8 | let finished = false; 9 | const waiter = async () => { 10 | await x.waitOne(); 11 | finished = true; 12 | }; 13 | const wait = waiter(); 14 | 15 | const lease = PromisePal.delay(TimeSpan.fromMilliseconds(700)); 16 | await Promise.race([wait, lease]); 17 | expect(finished).to.equal(false); 18 | 19 | x.set(); 20 | await PromisePal.delay(TimeSpan.fromMilliseconds(100)); 21 | expect(finished).to.equal(true); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/Clients/js/test/std/bcl/ConditionalWeakTable.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ArgumentNullError, 3 | AsyncAutoResetEvent, 4 | CancellationTokenSource, 5 | ConditionalWeakTable, 6 | OperationCanceledError, 7 | PromisePal, 8 | Timeout, 9 | TimeSpan, 10 | } from '../../../src/std'; 11 | 12 | import { expect } from 'chai'; 13 | import { PromiseStatus } from '../../../src/std/bcl/promises/PromiseStatus'; 14 | 15 | describe(`${ConditionalWeakTable.name}'s`, () => { 16 | const sut = new ConditionalWeakTable(); 17 | 18 | describe(`🌿 "getOrCreateValue" method`, () => { 19 | describe(`should not throw when called with valid args`, () => { 20 | const cases = [ 21 | [{}, (_: any) => "test"] as const, 22 | [() => { }, (_: any) => "test"] as const, 23 | ]; 24 | 25 | for (const [key, valueFactory] of cases) { 26 | it(`like ${JSON.stringify([key, valueFactory])}`, () => { 27 | const act = () => sut.getOrCreateValue(key, valueFactory); 28 | expect(act).to.not.throw(); 29 | }); 30 | } 31 | }); 32 | 33 | it(`should return consistent results`, () => { 34 | const SomeClass = class { }; 35 | const result = {}; 36 | 37 | let callCount = 0; 38 | const factory = () => { 39 | callCount++; 40 | return result; 41 | } 42 | 43 | expect(sut.getOrCreateValue(SomeClass, factory)).to.equal(result); 44 | expect(sut.getOrCreateValue(SomeClass, factory)).to.equal(result); 45 | expect(callCount).to.equal(1); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/Clients/js/test/std/bcl/PromiseCompletionSource.test.ts: -------------------------------------------------------------------------------- 1 | import { PromiseCompletionSource, PromisePal } from '../../../src/std'; 2 | import { expect } from 'chai'; 3 | 4 | describe(`${PromiseCompletionSource.name}`, function () { 5 | it('should work', async () => { 6 | const pcs = new PromiseCompletionSource(); 7 | const act = async () => { 8 | let failed; 9 | try { 10 | await pcs.promise; 11 | failed = false; 12 | } catch (x) { 13 | failed = true; 14 | throw x; 15 | } 16 | }; 17 | 18 | const error = new Error('Some Message'); 19 | 20 | async function parallel() { 21 | await PromisePal.delay(1); 22 | pcs.setFaulted(error); 23 | } 24 | 25 | parallel(); 26 | 27 | let caught: any = undefined; 28 | 29 | try { 30 | await act(); 31 | } catch (error) { 32 | caught = error; 33 | } 34 | 35 | expect(caught).to.equal(error); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /src/Clients/js/test/std/bcl/RandomCancellationToken.test.ts: -------------------------------------------------------------------------------- 1 | import { RandomCancellationToken } from '../../../src/std'; 2 | 3 | import { expect } from 'chai'; 4 | 5 | describe(`${RandomCancellationToken.name}'s`, () => { 6 | describe(`📞 "toString" static method`, () => { 7 | it(`should not throw`, () => { 8 | const act = () => RandomCancellationToken.toString(); 9 | expect(act).not.to.throw(); 10 | }); 11 | 12 | it(`should return "new CancellationToken()"`, () => { 13 | expect(RandomCancellationToken.toString()).to.equal('new CancellationToken()'); 14 | }); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/Clients/js/test/web/Contracts/IAlgebra.ts: -------------------------------------------------------------------------------- 1 | import { Message } from '../../../src/std'; 2 | 3 | export class IAlgebra { 4 | public MultiplySimple(x: number, y: number): Promise { 5 | throw void 0; 6 | } 7 | 8 | public Sleep(milliseconds: number): Promise { 9 | throw void 0; 10 | } 11 | 12 | public TestMessage(message: Message): Promise { 13 | throw void 0; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Clients/js/test/web/Contracts/IArithmetic.ts: -------------------------------------------------------------------------------- 1 | import { Message } from '../../../src/std'; 2 | 3 | 4 | export interface IArithmetic { 5 | Sum(x: number, y: number): Promise; 6 | SendMessage(message: Message): Promise; 7 | } 8 | -------------------------------------------------------------------------------- /src/Clients/js/test/web/Contracts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IAlgebra'; 2 | export * from './IArithmetic'; 3 | -------------------------------------------------------------------------------- /src/Clients/js/test/web/Fixtures/AlgebraProxy.ts: -------------------------------------------------------------------------------- 1 | import { proxyFactory } from './ProxyFactory'; 2 | import { IAlgebra } from '../Contracts'; 3 | 4 | export const algebraProxyFactory = () => proxyFactory.withService(IAlgebra); 5 | -------------------------------------------------------------------------------- /src/Clients/js/test/web/Fixtures/ProxyFactory.ts: -------------------------------------------------------------------------------- 1 | import { ipc } from '../../../src/web'; 2 | import { serverUrl } from './ServerUrl'; 3 | 4 | export const proxyFactory = ipc.proxy.withAddress(x => x.isWebSocket(serverUrl)); 5 | -------------------------------------------------------------------------------- /src/Clients/js/test/web/Fixtures/ServerUrl.ts: -------------------------------------------------------------------------------- 1 | export const serverUrl = 'ws://127.0.0.1:61234'; 2 | -------------------------------------------------------------------------------- /src/Clients/js/test/web/Fixtures/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ServerUrl'; 2 | export * from './ProxyFactory'; 3 | export * from './AlgebraProxy'; 4 | -------------------------------------------------------------------------------- /src/Clients/js/tsconfig.common.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "include": [], 4 | "exclude": [ 5 | "./node_modules/**/*", 6 | ], 7 | "compilerOptions": { 8 | "outDir": "./dist/obj/src", /* Specify an output folder for all emitted files. */ 9 | "rootDir": "./src", /* Specify the root folder within your source files. */ 10 | "baseUrl": ".", 11 | 12 | "declaration": true, 13 | 14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | "module": "commonjs", /* Specify what module code is generated. */ 16 | "resolveJsonModule": true, /* Enable importing .json files. */ 17 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 18 | "allowSyntheticDefaultImports": true, 19 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 20 | "strict": true, /* Enable all strict type-checking options. */ 21 | "skipLibCheck": true, /* Skip type checking all .d.ts files. */ 22 | "stripInternal": true 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /src/Clients/js/tsconfig.dotnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.common.json", 3 | "include": [ 4 | "test/dotnet/**/*" 5 | ], 6 | "exclude": [ 7 | ], 8 | "compilerOptions": { 9 | "outDir": "./dist/obj/dotnet/", 10 | "declaration": true, 11 | "rootDir": "." 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Clients/js/tsconfig.jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.common.json", 3 | "compilerOptions": { 4 | "module": "NodeNext", 5 | "target": "ESNext" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Clients/js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.common.json", 3 | "include": ["src/**/*"], 4 | "ts-node": { 5 | "compilerOptions": { 6 | "target": "ESNext", 7 | "module": "ES2022" 8 | } 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /src/Clients/js/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.common.json", 3 | "include": [ 4 | "src/std/**/*", 5 | "src/node/**/*" 6 | ], 7 | "exclude": [ 8 | "src/web/**", 9 | "**/*.web.ts" 10 | ], 11 | "compilerOptions": { 12 | "outDir": "./dist/prepack/node/", 13 | "declaration": true, 14 | "paths": { 15 | "@foundation": [ "node/foundation" ], 16 | "@foundation/*": [ "node/foundation/*" ], 17 | "@core": [ "node/core" ], 18 | "@core/*": [ "node/core/*" ] 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Clients/js/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist/obj/test", 5 | "rootDir": ".", /* Specify the root folder within your source files. */ 6 | "inlineSourceMap": true, 7 | "moduleResolution": "node" 8 | }, 9 | "include": [ 10 | "test/**/*.ts", 11 | "src/**/*.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/Clients/js/tsconfig.web-js.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.web.json", 3 | "compilerOptions": { 4 | "outDir": "./dist/prepack/web-js/", 5 | "declaration": false 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Clients/js/tsconfig.web.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.common.json", 3 | "include": [ 4 | "src/std/**/*", 5 | "src/web/**/*" 6 | ], 7 | "exclude": [ 8 | "src/node/**", 9 | "**/*.node.ts" 10 | ], 11 | "compilerOptions": { 12 | "outDir": "./dist/prepack/web/", 13 | "declaration": true, 14 | "paths": { 15 | "@foundation": [ "web/foundation" ], 16 | "@foundation/*": [ "web/foundation/*" ], 17 | "@core": [ "web/core" ], 18 | "@core/*": [ "web/core/*" ] 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Clients/js/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint:recommended" 4 | ], 5 | "rules": { 6 | "arrow-parens": [ 7 | true, 8 | "ban-single-arg-parens" 9 | ], 10 | "space-before-function-paren": false, 11 | "unified-signatures": false, 12 | "no-empty": false, 13 | "member-ordering": false, 14 | "interface-name": false, 15 | "max-classes-per-file": false, 16 | "max-line-length": [ 17 | true, 18 | 180 19 | ], 20 | "no-console": [ 21 | true, 22 | "time", 23 | "timeEnd", 24 | "trace" 25 | ], 26 | "no-string-literal": false, 27 | "object-literal-sort-keys": false, 28 | "ordered-imports": false, 29 | "quotemark": [ 30 | true, 31 | "single", 32 | "avoid-escape" 33 | ], 34 | "trailing-comma": [ 35 | true, 36 | { 37 | "multiline": "always", 38 | "singleline": "never" 39 | } 40 | ], 41 | "variable-name": [ 42 | true, 43 | "allow-leading-underscore", 44 | "ban-keywords", 45 | "check-format" 46 | ] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Clients/js/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const common = require('./webpack.common'); 2 | module.exports = common; 3 | -------------------------------------------------------------------------------- /src/IpcSample.ConsoleClient/App1.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/IpcSample.ConsoleClient/IpcSample.ConsoleClient.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net7.0;net461;net7.0-windows 6 | app1.manifest 7 | latest 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/IpcSample.ConsoleServer/App1.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/IpcSample.ConsoleServer/IpcSample.ConsoleServer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net7.0;net461;net7.0-windows 6 | app1.manifest 7 | latest 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/IpcSample.ConsoleServer/Server.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System.Diagnostics; 3 | using UiPath.CoreIpc.NamedPipe; 4 | 5 | namespace UiPath.CoreIpc.Tests; 6 | 7 | class Server 8 | { 9 | //private static readonly Timer _timer = new Timer(_ => 10 | //{ 11 | // Console.WriteLine("GC.Collect"); 12 | // GC.Collect(); 13 | // GC.WaitForPendingFinalizers(); 14 | // GC.Collect(); 15 | //}, null, 0, 3000); 16 | static async Task Main() 17 | { 18 | Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); 19 | //GuiLikeSyncContext.Install(); 20 | Console.WriteLine(SynchronizationContext.Current); 21 | var serviceProvider = ConfigureServices(); 22 | // build and run service host 23 | var host = new ServiceHostBuilder(serviceProvider) 24 | .UseNamedPipes(new NamedPipeSettings("test") 25 | { 26 | RequestTimeout = TimeSpan.FromSeconds(2), 27 | //AccessControl = security => security.AllowCurrentUser(), 28 | }) 29 | .AddEndpoint() 30 | .AddEndpoint() 31 | .ValidateAndBuild(); 32 | 33 | await await Task.WhenAny(host.RunAsync(), Task.Run(() => 34 | { 35 | Console.WriteLine(typeof(int).Assembly); 36 | Console.ReadLine(); 37 | host.Dispose(); 38 | })); 39 | 40 | Console.WriteLine("Server stopped."); 41 | } 42 | 43 | private static IServiceProvider ConfigureServices() => 44 | new ServiceCollection() 45 | .AddIpcWithLogging() 46 | .AddSingleton() 47 | .AddSingleton() 48 | .BuildServiceProvider(); 49 | } -------------------------------------------------------------------------------- /src/IpcSample.ConsoleServer/TcpServer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System.Diagnostics; 3 | using System.Net; 4 | using UiPath.CoreIpc.Tcp; 5 | 6 | namespace UiPath.CoreIpc.Tests; 7 | 8 | class TcpServer 9 | { 10 | static readonly IPEndPoint SystemEndPoint = new(IPAddress.Any, 3131); 11 | //private static readonly Timer _timer = new Timer(_ => 12 | //{ 13 | // Console.WriteLine("GC.Collect"); 14 | // GC.Collect(); 15 | // GC.WaitForPendingFinalizers(); 16 | // GC.Collect(); 17 | //}, null, 0, 3000); 18 | 19 | static async Task _Main() 20 | { 21 | Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); 22 | //GuiLikeSyncContext.Install(); 23 | Console.WriteLine(SynchronizationContext.Current); 24 | var serviceProvider = ConfigureServices(); 25 | // build and run service host 26 | var data = File.ReadAllBytes(@"../../../../localhost.pfx"); 27 | var host = new ServiceHostBuilder(serviceProvider) 28 | .UseTcp(new TcpSettings(SystemEndPoint) 29 | { 30 | RequestTimeout = TimeSpan.FromSeconds(2), 31 | //Certificate = new X509Certificate(data, "1"), 32 | }) 33 | .AddEndpoint() 34 | .AddEndpoint() 35 | .ValidateAndBuild(); 36 | 37 | await await Task.WhenAny(host.RunAsync(), Task.Run(() => 38 | { 39 | Console.WriteLine(typeof(int).Assembly); 40 | Console.ReadLine(); 41 | host.Dispose(); 42 | })); 43 | 44 | Console.WriteLine("Server stopped."); 45 | } 46 | 47 | private static IServiceProvider ConfigureServices() => 48 | new ServiceCollection() 49 | .AddIpcWithLogging() 50 | .AddSingleton() 51 | .AddSingleton() 52 | .BuildServiceProvider(); 53 | } -------------------------------------------------------------------------------- /src/IpcSample.ConsoleServer/WebSocketServer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System.Diagnostics; 3 | using System.Net; 4 | using System.Net.WebSockets; 5 | using UiPath.CoreIpc.WebSockets; 6 | namespace UiPath.CoreIpc.Tests; 7 | class WebSocketServer 8 | { 9 | //private static readonly Timer _timer = new Timer(_ => 10 | //{ 11 | // Console.WriteLine("GC.Collect"); 12 | // GC.Collect(); 13 | // GC.WaitForPendingFinalizers(); 14 | // GC.Collect(); 15 | //}, null, 0, 3000); 16 | 17 | static async Task _Main() 18 | { 19 | Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); 20 | //GuiLikeSyncContext.Install(); 21 | Console.WriteLine(SynchronizationContext.Current); 22 | var serviceProvider = ConfigureServices(); 23 | // build and run service host 24 | //var data = File.ReadAllBytes(@"../../../../localhost.pfx"); 25 | var host = new ServiceHostBuilder(serviceProvider) 26 | .UseWebSockets(new(new HttpSysWebSocketsListener("http://localhost:1212/wsDemo/").Accept) 27 | { 28 | RequestTimeout = TimeSpan.FromSeconds(2), 29 | //Certificate = new X509Certificate(data, "1"), 30 | }) 31 | .AddEndpoint() 32 | .AddEndpoint() 33 | .ValidateAndBuild(); 34 | await await Task.WhenAny(host.RunAsync(), Task.Run(() => 35 | { 36 | Console.WriteLine(typeof(int).Assembly); 37 | Console.ReadLine(); 38 | host.Dispose(); 39 | })); 40 | Console.WriteLine("Server stopped."); 41 | return; 42 | } 43 | private static IServiceProvider ConfigureServices() => 44 | new ServiceCollection() 45 | .AddIpcWithLogging() 46 | .AddSingleton() 47 | .AddSingleton() 48 | .BuildServiceProvider(); 49 | } -------------------------------------------------------------------------------- /src/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/UiPath.CoreIpc.Tests/Implementation/ComputingCallback.cs: -------------------------------------------------------------------------------- 1 | namespace UiPath.CoreIpc.Tests; 2 | 3 | public interface IComputingCallback 4 | { 5 | Task GetId(Message message); 6 | Task GetThreadName(); 7 | } 8 | public class ComputingCallback : IComputingCallback 9 | { 10 | public string Id { get; set; } 11 | public async Task GetId(Message message) 12 | { 13 | message.Client.ShouldBeNull(); 14 | return Id; 15 | } 16 | 17 | public async Task GetThreadName() => Thread.CurrentThread.Name; 18 | } -------------------------------------------------------------------------------- /src/UiPath.CoreIpc.Tests/TcpTests..cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using UiPath.CoreIpc.Tcp; 3 | namespace UiPath.CoreIpc.Tests; 4 | public class SystemTcpTests : SystemTests> 5 | { 6 | int _port = 3131 + GetCount(); 7 | protected override ServiceHostBuilder Configure(ServiceHostBuilder serviceHostBuilder) => 8 | serviceHostBuilder.UseTcp(Configure(new TcpSettings(GetEndPoint()))); 9 | protected override TcpClientBuilder CreateSystemClientBuilder() => new(GetEndPoint()); 10 | [Fact] 11 | public override async void BeforeCallServerSide() 12 | { 13 | _port++; 14 | base.BeforeCallServerSide(); 15 | } 16 | IPEndPoint GetEndPoint() => new(IPAddress.Loopback, _port); 17 | } 18 | public class ComputingTcpTests : ComputingTests> 19 | { 20 | protected static readonly IPEndPoint ComputingEndPoint = new(IPAddress.Loopback, 2121+GetCount()); 21 | protected override TcpClientBuilder ComputingClientBuilder(TaskScheduler taskScheduler = null) => 22 | new TcpClientBuilder(ComputingEndPoint, _serviceProvider) 23 | .RequestTimeout(RequestTimeout) 24 | .CallbackInstance(_computingCallback) 25 | .TaskScheduler(taskScheduler); 26 | protected override ServiceHostBuilder Configure(ServiceHostBuilder serviceHostBuilder) => 27 | serviceHostBuilder.UseTcp(Configure(new TcpSettings(ComputingEndPoint))); 28 | } -------------------------------------------------------------------------------- /src/UiPath.CoreIpc.Tests/TestBase.cs: -------------------------------------------------------------------------------- 1 | using Nito.AsyncEx; 2 | 3 | namespace UiPath.CoreIpc.Tests; 4 | 5 | public abstract class TestBase : IDisposable 6 | { 7 | protected const int MaxReceivedMessageSizeInMegabytes = 1; 8 | protected static int Count = -1; 9 | public static readonly TimeSpan RequestTimeout = 10 | #if CI 11 | TimeSpan.FromSeconds(2) + 12 | #endif 13 | (Debugger.IsAttached ? TimeSpan.FromDays(1) : TimeSpan.FromSeconds(2)); 14 | protected readonly IServiceProvider _serviceProvider; 15 | protected readonly AsyncContext _guiThread = new AsyncContextThread().Context; 16 | 17 | //static TestBase() 18 | //{ 19 | // AppContext.SetSwitch("Switch.System.Net.DontEnableSystemDefaultTlsVersions", false); 20 | //} 21 | public TestBase() 22 | { 23 | _guiThread.SynchronizationContext.Send(() => Thread.CurrentThread.Name = "GuiThread"); 24 | _serviceProvider = IpcHelpers.ConfigureServices(); 25 | } 26 | 27 | protected static int GetCount() => Interlocked.Increment(ref Count); 28 | 29 | protected TaskScheduler GuiScheduler => _guiThread.Scheduler; 30 | 31 | public virtual void Dispose() => _guiThread.Dispose(); 32 | protected virtual TSettings Configure(TSettings listenerSettings) where TSettings : ListenerSettings 33 | { 34 | listenerSettings.RequestTimeout = RequestTimeout; 35 | listenerSettings.MaxReceivedMessageSizeInMegabytes = MaxReceivedMessageSizeInMegabytes; 36 | return listenerSettings; 37 | } 38 | protected abstract ServiceHostBuilder Configure(ServiceHostBuilder serviceHostBuilder); 39 | } -------------------------------------------------------------------------------- /src/UiPath.CoreIpc.Tests/UiPath.CoreIpc.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0;net461;net6.0-windows 5 | $(NoWarn);1998 6 | $(DefineConstants);$(DefineConstantsEx) 7 | latest 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/UiPath.CoreIpc/CancellationTokenSourcePool.cs: -------------------------------------------------------------------------------- 1 | namespace UiPath.CoreIpc; 2 | // https://github.com/dotnet/aspnetcore/blob/main/src/Shared/CancellationTokenSourcePool.cs 3 | internal static class CancellationTokenSourcePool 4 | { 5 | public static PooledCancellationTokenSource Rent() => 6 | #if !NET461 7 | ObjectPool.Rent(); 8 | #else 9 | new(); 10 | #endif 11 | static bool Return(PooledCancellationTokenSource cts) => ObjectPool.Return(cts); 12 | public sealed class PooledCancellationTokenSource : CancellationTokenSource 13 | { 14 | public void Return() 15 | { 16 | // If we failed to return to the pool then dispose 17 | #if !NET461 18 | if (!TryReset() || !CancellationTokenSourcePool.Return(this)) 19 | #endif 20 | { 21 | Dispose(); 22 | } 23 | } 24 | } 25 | } 26 | static class ObjectPool where T : new() 27 | { 28 | private const int MaxQueueSize = 1024; 29 | private static readonly ConcurrentQueue Cache = new(); 30 | private static int Count; 31 | public static T Rent() 32 | { 33 | if (Cache.TryDequeue(out var cts)) 34 | { 35 | Interlocked.Decrement(ref Count); 36 | return cts; 37 | } 38 | return new(); 39 | } 40 | public static bool Return(T item) 41 | { 42 | if (Interlocked.Increment(ref Count) > MaxQueueSize) 43 | { 44 | Interlocked.Decrement(ref Count); 45 | return false; 46 | } 47 | Cache.Enqueue(item); 48 | return true; 49 | } 50 | } -------------------------------------------------------------------------------- /src/UiPath.CoreIpc/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | using System.Diagnostics.CodeAnalysis; 6 | [assembly: SuppressMessage("Performance", "HAA0505:Initializer reference type allocation", Scope = "module")] 7 | [assembly: SuppressMessage("Performance", "HAA0502:Explicit new reference type allocation", Scope = "module")] 8 | [assembly: SuppressMessage("Performance", "HAA0501:Explicit new array type allocation", Scope = "module")] 9 | #if NET461 10 | namespace System.Runtime.CompilerServices; 11 | internal static class IsExternalInit 12 | { 13 | } 14 | #endif -------------------------------------------------------------------------------- /src/UiPath.CoreIpc/Server/ServiceHost.cs: -------------------------------------------------------------------------------- 1 | namespace UiPath.CoreIpc; 2 | public sealed class ServiceHost : IDisposable 3 | { 4 | private readonly CancellationTokenSource _cancellationTokenSource = new(); 5 | private readonly IDictionary _endpoints; 6 | private readonly IReadOnlyCollection _listeners; 7 | internal ServiceHost(IEnumerable listeners, IDictionary endpoints) 8 | { 9 | _endpoints = endpoints.ToReadOnlyDictionary(); 10 | _listeners = listeners.ToArray(); 11 | } 12 | public void Dispose() 13 | { 14 | if(_cancellationTokenSource.IsCancellationRequested) 15 | { 16 | return; 17 | } 18 | foreach (var listener in _listeners) 19 | { 20 | listener.Dispose(); 21 | } 22 | _cancellationTokenSource.Cancel(); 23 | _cancellationTokenSource.AssertDisposed(); 24 | } 25 | public void Run() => RunAsync().Wait(); 26 | public Task RunAsync(TaskScheduler taskScheduler = null) 27 | { 28 | foreach (var endpoint in _endpoints.Values) 29 | { 30 | endpoint.Scheduler = taskScheduler; 31 | } 32 | return Task.Run(() => Task.WhenAll(_listeners.Select(listener => listener.Listen(_cancellationTokenSource.Token)))); 33 | } 34 | } -------------------------------------------------------------------------------- /src/UiPath.CoreIpc/TaskCompletionPool.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks.Sources; 2 | namespace UiPath.CoreIpc; 3 | internal static class TaskCompletionPool 4 | { 5 | public static ManualResetValueTaskSource Rent() => ObjectPool.Rent(); 6 | static void Return(ManualResetValueTaskSource source) => ObjectPool.Return(source); 7 | public sealed class ManualResetValueTaskSource : IValueTaskSource, IValueTaskSource 8 | { 9 | private ManualResetValueTaskSourceCore _core; // mutable struct; do not make this readonly 10 | public bool RunContinuationsAsynchronously { get => _core.RunContinuationsAsynchronously; set => _core.RunContinuationsAsynchronously = value; } 11 | public short Version => _core.Version; 12 | public ValueTask ValueTask() => new(this, Version); 13 | public void Reset() => _core.Reset(); 14 | public void SetResult(T result) => _core.SetResult(result); 15 | public void SetException(Exception error) => _core.SetException(error); 16 | public void SetCanceled() => _core.SetException(new TaskCanceledException()); 17 | public T GetResult(short token) => _core.GetResult(token); 18 | void IValueTaskSource.GetResult(short token) => _core.GetResult(token); 19 | public ValueTaskSourceStatus GetStatus(short token) => _core.GetStatus(token); 20 | public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _core.OnCompleted(continuation, state, token, flags); 21 | public void Return() 22 | { 23 | Reset(); 24 | TaskCompletionPool.Return(this); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/UiPath.CoreIpc/Tcp/TcpClient.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Sockets; 3 | 4 | namespace UiPath.CoreIpc.Tcp; 5 | 6 | using ConnectionFactory = Func>; 7 | using BeforeCallHandler = Func; 8 | interface ITcpKey : IConnectionKey 9 | { 10 | IPEndPoint EndPoint { get; } 11 | } 12 | class TcpClient : ServiceClient, ITcpKey where TInterface : class 13 | { 14 | 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) 15 | { 16 | EndPoint = endPoint; 17 | HashCode = (EndPoint, sslServer).GetHashCode(); 18 | } 19 | public override string Name => base.Name ?? EndPoint.ToString(); 20 | public IPEndPoint EndPoint { get; } 21 | public override bool Equals(IConnectionKey other) => other == this || (other is ITcpKey otherClient && EndPoint.Equals(otherClient.EndPoint) && 22 | base.Equals(other)); 23 | public override ClientConnection CreateClientConnection() => new TcpClientConnection(this); 24 | class TcpClientConnection : ClientConnection 25 | { 26 | private TcpClient _tcpClient; 27 | public TcpClientConnection(IConnectionKey connectionKey) : base(connectionKey) {} 28 | public override bool Connected => _tcpClient?.Client?.Connected is true; 29 | protected override void Dispose(bool disposing) 30 | { 31 | _tcpClient?.Dispose(); 32 | base.Dispose(disposing); 33 | } 34 | public override async Task Connect(CancellationToken cancellationToken) 35 | { 36 | _tcpClient = new(); 37 | var endPoint = ((ITcpKey)ConnectionKey).EndPoint; 38 | await _tcpClient.ConnectAsync(endPoint.Address, endPoint.Port, cancellationToken); 39 | return _tcpClient.GetStream(); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/UiPath.CoreIpc/Tcp/TcpClientBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace UiPath.CoreIpc.Tcp; 4 | 5 | public abstract class TcpClientBuilderBase : ServiceClientBuilder where TInterface : class where TDerived : ServiceClientBuilder 6 | { 7 | private readonly IPEndPoint _endPoint; 8 | 9 | protected TcpClientBuilderBase(IPEndPoint endPoint, Type callbackContract = null, IServiceProvider serviceProvider = null) : base(callbackContract, serviceProvider) => 10 | _endPoint = endPoint; 11 | 12 | protected override TInterface BuildCore(EndpointSettings serviceEndpoint) => 13 | new TcpClient(_endPoint, _serializer, _requestTimeout, _logger, _connectionFactory, _sslServer, _beforeCall, _objectParameters, serviceEndpoint).CreateProxy(); 14 | } 15 | 16 | public class TcpClientBuilder : TcpClientBuilderBase, TInterface> where TInterface : class 17 | { 18 | public TcpClientBuilder(IPEndPoint endPoint) : base(endPoint){} 19 | } 20 | 21 | public class TcpClientBuilder : TcpClientBuilderBase, TInterface> where TInterface : class where TCallbackInterface : class 22 | { 23 | public TcpClientBuilder(IPEndPoint endPoint, IServiceProvider serviceProvider) : base(endPoint, typeof(TCallbackInterface), serviceProvider) { } 24 | 25 | public TcpClientBuilder CallbackInstance(TCallbackInterface singleton) 26 | { 27 | _callbackInstance = singleton; 28 | return this; 29 | } 30 | 31 | public TcpClientBuilder TaskScheduler(TaskScheduler taskScheduler) 32 | { 33 | _taskScheduler = taskScheduler; 34 | return this; 35 | } 36 | } -------------------------------------------------------------------------------- /src/UiPath.CoreIpc/Tcp/TcpListener.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | namespace UiPath.CoreIpc.Tcp; 3 | 4 | public class TcpSettings : ListenerSettings 5 | { 6 | public TcpSettings(IPEndPoint endPoint) : base(endPoint.ToString()) 7 | { 8 | EndPoint = endPoint; 9 | } 10 | public IPEndPoint EndPoint { get; } 11 | } 12 | class TcpListener : Listener 13 | { 14 | readonly System.Net.Sockets.TcpListener _tcpServer; 15 | public TcpListener(ListenerSettings settings) : base(settings) 16 | { 17 | _tcpServer = new(Settings.EndPoint); 18 | _tcpServer.Start(backlog: Settings.ConcurrentAccepts); 19 | } 20 | public new TcpSettings Settings => (TcpSettings)base.Settings; 21 | protected override ServerConnection CreateServerConnection() => new TcpServerConnection(this); 22 | protected override void Dispose(bool disposing) 23 | { 24 | base.Dispose(disposing); 25 | _tcpServer.Stop(); 26 | } 27 | Task AcceptClient(CancellationToken cancellationToken) => _tcpServer.AcceptTcpClientAsync(); 28 | class TcpServerConnection : ServerConnection 29 | { 30 | System.Net.Sockets.TcpClient _tcpClient; 31 | public TcpServerConnection(Listener listener) : base(listener){} 32 | public override async Task AcceptClient(CancellationToken cancellationToken) 33 | { 34 | _tcpClient = await ((TcpListener)_listener).AcceptClient(cancellationToken); 35 | return _tcpClient.GetStream(); 36 | } 37 | protected override void Dispose(bool disposing) 38 | { 39 | _tcpClient?.Dispose(); 40 | base.Dispose(disposing); 41 | } 42 | } 43 | } 44 | public static class TcpServiceExtensions 45 | { 46 | public static ServiceHostBuilder UseTcp(this ServiceHostBuilder builder, TcpSettings settings) => builder.AddListener(new TcpListener(settings)); 47 | } -------------------------------------------------------------------------------- /src/UiPath.CoreIpc/WebSockets/WebSocketClient.cs: -------------------------------------------------------------------------------- 1 | using System.Net.WebSockets; 2 | namespace UiPath.CoreIpc.WebSockets; 3 | using ConnectionFactory = Func>; 4 | using BeforeCallHandler = Func; 5 | interface IWebSocketsKey : IConnectionKey 6 | { 7 | Uri Uri { get; } 8 | } 9 | class WebSocketClient : ServiceClient, IWebSocketsKey where TInterface : class 10 | { 11 | 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) 12 | { 13 | Uri = uri; 14 | HashCode = (uri, sslServer).GetHashCode(); 15 | } 16 | public override string Name => base.Name ?? Uri.ToString(); 17 | public Uri Uri { get; } 18 | public override bool Equals(IConnectionKey other) => other == this || (other is IWebSocketsKey otherClient && Uri.Equals(otherClient.Uri) && base.Equals(other)); 19 | public override ClientConnection CreateClientConnection() => new WebSocketClientConnection(this); 20 | class WebSocketClientConnection : ClientConnection 21 | { 22 | ClientWebSocket _clientWebSocket; 23 | public WebSocketClientConnection(IConnectionKey connectionKey) : base(connectionKey) {} 24 | public override bool Connected => _clientWebSocket?.State == WebSocketState.Open; 25 | protected override void Dispose(bool disposing) 26 | { 27 | _clientWebSocket?.Dispose(); 28 | base.Dispose(disposing); 29 | } 30 | public override async Task Connect(CancellationToken cancellationToken) 31 | { 32 | _clientWebSocket = new(); 33 | var uri = ((IWebSocketsKey)ConnectionKey).Uri; 34 | await _clientWebSocket.ConnectAsync(uri, cancellationToken); 35 | return new WebSocketStream(_clientWebSocket); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/UiPath.CoreIpc/WebSockets/WebSocketClientBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace UiPath.CoreIpc.WebSockets; 2 | public abstract class WebSocketClientBuilderBase : ServiceClientBuilder where TInterface : class where TDerived : ServiceClientBuilder 3 | { 4 | private readonly Uri _uri; 5 | protected WebSocketClientBuilderBase(Uri uri, Type callbackContract = null, IServiceProvider serviceProvider = null) : base(callbackContract, serviceProvider) => 6 | _uri = uri; 7 | protected override TInterface BuildCore(EndpointSettings serviceEndpoint) => 8 | new WebSocketClient(_uri, _serializer, _requestTimeout, _logger, _connectionFactory, _sslServer, _beforeCall, _objectParameters, serviceEndpoint).CreateProxy(); 9 | } 10 | public class WebSocketClientBuilder : WebSocketClientBuilderBase, TInterface> where TInterface : class 11 | { 12 | public WebSocketClientBuilder(Uri uri) : base(uri){} 13 | } 14 | public class WebSocketClientBuilder : WebSocketClientBuilderBase, TInterface> where TInterface : class where TCallbackInterface : class 15 | { 16 | public WebSocketClientBuilder(Uri uri, IServiceProvider serviceProvider) : base(uri, typeof(TCallbackInterface), serviceProvider) { } 17 | public WebSocketClientBuilder CallbackInstance(TCallbackInterface singleton) 18 | { 19 | _callbackInstance = singleton; 20 | return this; 21 | } 22 | public WebSocketClientBuilder TaskScheduler(TaskScheduler taskScheduler) 23 | { 24 | _taskScheduler = taskScheduler; 25 | return this; 26 | } 27 | } -------------------------------------------------------------------------------- /src/UiPath.CoreIpc/WebSockets/WebSocketListener.cs: -------------------------------------------------------------------------------- 1 | using System.Net.WebSockets; 2 | namespace UiPath.CoreIpc.WebSockets; 3 | using Accept = Func>; 4 | public class WebSocketSettings : ListenerSettings 5 | { 6 | public WebSocketSettings(Accept accept) : base("") => Accept = accept; 7 | public Accept Accept { get; } 8 | } 9 | class WebSocketListener : Listener 10 | { 11 | public WebSocketListener(ListenerSettings settings) : base(settings){} 12 | protected override ServerConnection CreateServerConnection() => new WebSocketConnection(this); 13 | class WebSocketConnection : ServerConnection 14 | { 15 | public WebSocketConnection(Listener listener) : base(listener){} 16 | public override async Task AcceptClient(CancellationToken cancellationToken) => 17 | new WebSocketStream(await ((WebSocketSettings)_listener.Settings).Accept(cancellationToken)); 18 | } 19 | } 20 | public static class WebSocketServiceExtensions 21 | { 22 | public static ServiceHostBuilder UseWebSockets(this ServiceHostBuilder builder, WebSocketSettings settings) => 23 | builder.AddListener(new WebSocketListener(settings)); 24 | } --------------------------------------------------------------------------------