private async Task OnExecuteAsync() { //Console.WriteLine("Personal and Business Banking, Payments, and Digital Asset Management"); //Console.WriteLine("Banking: Store, transfer, and receive interest on multiple digital assets"); //Console.WriteLine("Payments: Make or accept instant payments using various currencies, online and in store"); //Console.WriteLine("Digital Asset Management: Issue your own tokens within seconds"); //Console.WriteLine(""); if (RunJsonRPCServer) { //while(true) //{ // var s = Console.ReadLine(); // if (s == null) // break; // File.AppendAllText("c:\\tmp\\input.txt", s + "\n"); //} await RespondToRpcRequestsAsync(FullDuplexStream.Splice(Console.OpenStandardInput(), Console.OpenStandardOutput()), 0); } else { Console.WriteLine($"{LyraGlobal.PRODUCTNAME} Command Line Client"); Console.WriteLine("Version: " + LyraGlobal.NODE_VERSION); Console.WriteLine($"\nCurrent networkd ID: {NetworkId}\n"); var mgr = new WalletManager(); await mgr.RunWalletAsync(this); } }
public void CanTimeout() { var readableMock = new Mock <Stream>(); readableMock.SetupGet(s => s.CanRead).Returns(true); var writableMock = new Mock <Stream>(); writableMock.SetupGet(s => s.CanWrite).Returns(true); var duplex = FullDuplexStream.Splice(readableMock.Object, writableMock.Object); Assert.False(duplex.CanTimeout); readableMock.SetupGet(s => s.CanTimeout).Returns(true); Assert.True(duplex.CanTimeout); readableMock.SetupGet(s => s.CanTimeout).Returns(false); writableMock.SetupGet(s => s.CanTimeout).Returns(true); Assert.True(duplex.CanTimeout); writableMock.SetupGet(s => s.CanTimeout).Returns(false); Assert.False(duplex.CanTimeout); duplex.Dispose(); Assert.False(duplex.CanTimeout); }
public async Task InitializeAsync() { var mx1TraceSource = new TraceSource(nameof(this.mx1), SourceLevels.All); var mx2TraceSource = new TraceSource(nameof(this.mx2), SourceLevels.All); mx1TraceSource.Listeners.Add(new XunitTraceListener(this.Logger)); mx2TraceSource.Listeners.Add(new XunitTraceListener(this.Logger)); Func <string, int, string, TraceSource> traceSourceFactory = (string mxInstanceName, int id, string name) => { var traceSource = new TraceSource(mxInstanceName + " channel " + id, SourceLevels.All); traceSource.Listeners.Add(new XunitTraceListener(this.Logger)); return(traceSource); }; Func <int, string, TraceSource> mx1TraceSourceFactory = (int id, string name) => traceSourceFactory(nameof(this.mx1), id, name); Func <int, string, TraceSource> mx2TraceSourceFactory = (int id, string name) => traceSourceFactory(nameof(this.mx2), id, name); (this.transport1, this.transport2) = FullDuplexStream.CreatePair(new System.IO.Pipelines.PipeOptions(pauseWriterThreshold: 2 * 1024 * 1024)); var mx1 = MultiplexingStream.CreateAsync(this.transport1, new MultiplexingStream.Options { TraceSource = mx1TraceSource, DefaultChannelTraceSourceFactory = mx1TraceSourceFactory }, this.TimeoutToken); var mx2 = MultiplexingStream.CreateAsync(this.transport2, new MultiplexingStream.Options { TraceSource = mx2TraceSource, DefaultChannelTraceSourceFactory = mx2TraceSourceFactory }, this.TimeoutToken); this.mx1 = await mx1; this.mx2 = await mx2; }
public async Task TransmitOverPreexistingPipeAndDisposeChannel(int length) { var buffer = this.GetBuffer(length); var pipePair = FullDuplexStream.CreatePipePair(); const string channelName = "a"; var mx1ChannelTask = this.mx1.OfferChannelAsync(channelName, new MultiplexingStream.ChannelOptions { ExistingPipe = pipePair.Item1 }, this.TimeoutToken); var mx2ChannelTask = this.mx2.AcceptChannelAsync(channelName, this.TimeoutToken); var(a, b) = await Task.WhenAll(mx1ChannelTask, mx2ChannelTask).WithCancellation(this.TimeoutToken); await pipePair.Item2.Output.WriteAsync(buffer, this.TimeoutToken); a.Dispose(); // In this scenario, there is actually no guarantee that bytes written previously were transmitted before the Channel was disposed. // In practice, folks with ExistingPipe set should complete their writer instead of disposing so the channel can dispose when writing (on both sides) is done. // In order for the b stream to recognize the closure, it does need to have read all the bytes that *were* transmitted though, // so drain the pipe insofar as it has bytes. Just don't assert how many were read. await this.DrainReaderTillCompletedAsync(b.Input); #pragma warning disable CS0618 // Type or member is obsolete await b.Input.WaitForWriterCompletionAsync().WithCancellation(this.TimeoutToken); #pragma warning restore CS0618 // Type or member is obsolete }
public async Task OfferReadOnlyPipe() { // Prepare a readonly pipe that is already fully populated with data for the other end to read. var pipePair = FullDuplexStream.CreatePipePair(); pipePair.Item1.Input.Complete(); // we don't read -- we only write. await pipePair.Item1.Output.WriteAsync(new byte[] { 1, 2, 3 }, this.TimeoutToken); pipePair.Item1.Output.Complete(); var ch1 = this.mx1.CreateChannel(new MultiplexingStream.ChannelOptions { ExistingPipe = pipePair.Item2 }); await this.WaitForEphemeralChannelOfferToPropagateAsync(); var ch2 = this.mx2.AcceptChannel(ch1.Id); var readResult = await ch2.Input.ReadAsync(this.TimeoutToken); Assert.Equal(3, readResult.Buffer.Length); ch2.Input.AdvanceTo(readResult.Buffer.End); readResult = await ch2.Input.ReadAsync(this.TimeoutToken); Assert.True(readResult.IsCompleted); ch2.Output.Complete(); await Task.WhenAll(ch1.Completion, ch2.Completion).WithCancellation(this.TimeoutToken); }
public async Task OfferWriteOnlyPipe() { var pipePair = FullDuplexStream.CreatePipePair(); pipePair.Item1.Output.Complete(); // we don't write -- we only read. var ch1 = this.mx1.CreateChannel(new MultiplexingStream.ChannelOptions { ExistingPipe = pipePair.Item2 }); await this.WaitForEphemeralChannelOfferToPropagateAsync(); var ch2 = this.mx2.AcceptChannel(ch1.Id); // Confirm that any attempt to read from the channel is immediately completed. var readResult = await ch2.Input.ReadAsync(this.TimeoutToken); Assert.True(readResult.IsCompleted); // Now write to the channel. await ch2.Output.WriteAsync(new byte[] { 1, 2, 3 }, this.TimeoutToken); ch2.Output.Complete(); readResult = await pipePair.Item1.Input.ReadAsync(this.TimeoutToken); Assert.Equal(3, readResult.Buffer.Length); pipePair.Item1.Input.AdvanceTo(readResult.Buffer.End); readResult = await pipePair.Item1.Input.ReadAsync(this.TimeoutToken); Assert.True(readResult.IsCompleted); await Task.WhenAll(ch1.Completion, ch2.Completion).WithCancellation(this.TimeoutToken); }
private LanguageServerTarget CreateLanguageServer(out JsonRpc serverJsonRpc, out IAsynchronousOperationListenerProvider listenerProvider) { using var workspace = TestWorkspace.CreateCSharp("", composition: Composition); var(_, serverStream) = FullDuplexStream.CreatePair(); var dispatcherFactory = workspace.GetService <RequestDispatcherFactory>(); var lspWorkspaceRegistrationService = workspace.GetService <ILspWorkspaceRegistrationService>(); var capabilitiesProvider = workspace.GetService <DefaultCapabilitiesProvider>(); var globalOptions = workspace.GetService <IGlobalOptionService>(); listenerProvider = workspace.GetService <IAsynchronousOperationListenerProvider>(); serverJsonRpc = new JsonRpc(new HeaderDelimitedMessageHandler(serverStream, serverStream)) { ExceptionStrategy = ExceptionProcessing.ISerializable, }; var languageServer = new LanguageServerTarget( dispatcherFactory, serverJsonRpc, capabilitiesProvider, lspWorkspaceRegistrationService, globalOptions, listenerProvider, NoOpLspLogger.Instance, ProtocolConstants.RoslynLspLanguages, clientName: null, userVisibleServerName: string.Empty, telemetryServerTypeName: string.Empty); serverJsonRpc.StartListening(); return(languageServer); }
public async Task AddLocalRpcTarget_OfT_ActualClass() { var streams = FullDuplexStream.CreateStreams(); this.serverStream = streams.Item1; this.clientStream = streams.Item2; this.serverRpc = new JsonRpc(this.serverStream); this.serverRpc.AddLocalRpcTarget <Server>(this.server, null); this.serverRpc.StartListening(); this.clientRpc = new JsonRpc(this.clientStream); var eventRaised = new TaskCompletionSource <EventArgs>(); this.clientRpc.AddLocalRpcMethod(nameof(IServer.InterfaceEvent), new Action <EventArgs>(eventRaised.SetResult)); var explicitEventRaised = new TaskCompletionSource <EventArgs>(); this.clientRpc.AddLocalRpcMethod(nameof(IServer.ExplicitInterfaceImplementation_Event), new Action <EventArgs>(explicitEventRaised.SetResult)); var classOnlyEventRaised = new TaskCompletionSource <EventArgs>(); this.clientRpc.AddLocalRpcMethod(nameof(Server.ServerEvent), new Action <EventArgs>(classOnlyEventRaised.SetResult)); this.clientRpc.StartListening(); // Verify that ordinary interface events can be raised. this.server.TriggerInterfaceEvent(new EventArgs()); await eventRaised.Task.WithCancellation(this.TimeoutToken); // Verify that explicit interface implementation events can also be raised. this.server.TriggerExplicitInterfaceImplementationEvent(new EventArgs()); await Assert.ThrowsAnyAsync <OperationCanceledException>(() => explicitEventRaised.Task.WithCancellation(ExpectedTimeoutToken)); // Verify that events that are NOT on the interface can be raised. this.server.TriggerEvent(new EventArgs()); await classOnlyEventRaised.Task.WithCancellation(this.TimeoutToken); }
public async Task BasicJsonRpc() { var(clientStream, serverStream) = FullDuplexStream.CreatePair(); var clientFormatter = new MessagePackFormatter(); var serverFormatter = new MessagePackFormatter(); var clientHandler = new LengthHeaderMessageHandler(clientStream.UsePipe(), clientFormatter); var serverHandler = new LengthHeaderMessageHandler(serverStream.UsePipe(), serverFormatter); var clientRpc = new JsonRpc(clientHandler); var serverRpc = new JsonRpc(serverHandler, new Server()); serverRpc.TraceSource = new TraceSource("Server", SourceLevels.Verbose); clientRpc.TraceSource = new TraceSource("Client", SourceLevels.Verbose); serverRpc.TraceSource.Listeners.Add(new XunitTraceListener(this.Logger)); clientRpc.TraceSource.Listeners.Add(new XunitTraceListener(this.Logger)); clientRpc.StartListening(); serverRpc.StartListening(); int result = await clientRpc.InvokeAsync <int>(nameof(Server.Add), 3, 5).WithCancellation(this.TimeoutToken); Assert.Equal(8, result); }
private async Task <(InProcLanguageServer.TestAccessor, List <LSP.PublishDiagnosticParams>)> RunPublishDiagnosticsAsync(TestWorkspace workspace, IDiagnosticService diagnosticService, int expectedNumberOfCallbacks, params Document[] documentsToPublish) { var(clientStream, serverStream) = FullDuplexStream.CreatePair(); var languageServer = CreateLanguageServer(serverStream, serverStream, workspace, diagnosticService); // Notification target for tests to recieve the notification details var callback = new Callback(expectedNumberOfCallbacks); using var jsonRpc = new JsonRpc(clientStream, clientStream, callback); // The json rpc messages won't necessarily come back in order by default. // So use a synchronization context to preserve the original ordering. // https://github.com/microsoft/vs-streamjsonrpc/blob/bc970c61b90db5db135a1b3d1c72ef355c2112af/doc/resiliency.md#when-message-order-is-important jsonRpc.SynchronizationContext = new RpcOrderPreservingSynchronizationContext(); jsonRpc.StartListening(); // Triggers language server to send notifications. foreach (var document in documentsToPublish) { await languageServer.PublishDiagnosticsAsync(document).ConfigureAwait(false); } // Waits for all notifications to be recieved. await callback.CallbackCompletedTask.Task.ConfigureAwait(false); return(languageServer.GetTestAccessor(), callback.Results);
public async Task PipePair() { var(party1, party2) = FullDuplexStream.CreatePipePair(); // First party indicates they're done sending messages (but might still be reading). party1.Output.Complete(); #pragma warning disable CS0618 // Type or member is obsolete // Second party recognizes that the other's writing is done, and acknowledges that they're done reading. await party2.Input.WaitForWriterCompletionAsync().WithCancellation(this.TimeoutToken); party2.Input.Complete(); await party1.Output.WaitForReaderCompletionAsync().WithCancellation(this.TimeoutToken); // just to show propagation. // Second party indicates that they're done writing messages. party2.Output.Complete(); // First party recognizes that the other's writing is done, and acknowledges that they're done reading. await party1.Input.WaitForWriterCompletionAsync().WithCancellation(this.TimeoutToken); party1.Input.Complete(); await party2.Output.WaitForReaderCompletionAsync().WithCancellation(this.TimeoutToken); // just to show propagation. #pragma warning restore RS0030 // Do not used banned APIs }
public async Task NotifyWithPipe_IsRejectedAtClient() { (IDuplexPipe, IDuplexPipe)duplexPipes = FullDuplexStream.CreatePipePair(); var ex = await Assert.ThrowsAnyAsync <Exception>(() => this.clientRpc.NotifyAsync(nameof(Server.AcceptReadableStream), "fileName", duplexPipes.Item2)); Assert.IsType <NotSupportedException>(ex.InnerException); }
public void NonTaskReturningMethod() { var streams = FullDuplexStream.CreateStreams(); var exception = Assert.Throws <NotSupportedException>(() => JsonRpc.Attach <IServerWithNonTaskReturnTypes>(streams.Item1)); this.Logger.WriteLine(exception.Message); }
public void InternalInterface() { // When implementing internal interfaces work, fill out this test to actually invoke it. var streams = FullDuplexStream.CreateStreams(); Assert.Throws <TypeLoadException>(() => JsonRpc.Attach <IServerInternal>(streams.Item1)); }
public Task <Stream> RequestServiceAsync(string serviceName, CancellationToken cancellationToken) { switch (serviceName) { case WellKnownRemoteHostServices.RemoteHostService: { var tuple = FullDuplexStream.CreateStreams(); return(Task.FromResult <Stream>(new WrappedStream(new RemoteHostService(tuple.Item1, _serviceProvider), tuple.Item2))); } case WellKnownServiceHubServices.CodeAnalysisService: { var tuple = FullDuplexStream.CreateStreams(); return(Task.FromResult <Stream>(new WrappedStream(new CodeAnalysisService(tuple.Item1, _serviceProvider), tuple.Item2))); } case WellKnownServiceHubServices.SnapshotService: { var tuple = FullDuplexStream.CreateStreams(); return(Task.FromResult <Stream>(new WrappedStream(new SnapshotService(tuple.Item1, _serviceProvider), tuple.Item2))); } case WellKnownServiceHubServices.RemoteSymbolSearchUpdateEngine: { var tuple = FullDuplexStream.CreateStreams(); return(Task.FromResult <Stream>(new WrappedStream(new RemoteSymbolSearchUpdateEngine(tuple.Item1, _serviceProvider), tuple.Item2))); } } throw ExceptionUtilities.UnexpectedValue(serviceName); }
public void ProxyTypeIsReused() { var streams = FullDuplexStream.CreateStreams(); var clientRpc = JsonRpc.Attach <IServerDerived>(streams.Item1); Assert.IsType(this.clientRpc.GetType(), clientRpc); }
static void Main(string[] args) { Console.OutputEncoding = Encoding.UTF8; // Here we use two connected streams to simulate the console I/O // Content written to streams.Item1 will be read from streams.Item2, vice versa. var streams = FullDuplexStream.CreatePair(); // Let's start the test client first. var clientTask = RunClientAsync(streams.Item2); // Configure & build service host var host = BuildServiceHost(); // Messages come from Stream var serverHandler = new StreamRpcServerHandler(host); // Though it's suggested that all feature types be interface types, for sake of // simplicity, here we just use a concrete class. var session = new LibrarySessionFeature(); serverHandler.DefaultFeatures.Set(session); // Connect the MessageReader/Writer to the handler. // If we want server to stop, just stop the source using (var reader = new ByLineTextMessageReader(streams.Item1)) using (var writer = new ByLineTextMessageWriter(streams.Item1)) using (serverHandler.Attach(reader, writer)) { // Wait for exit session.CancellationToken.WaitHandle.WaitOne(); } Console.WriteLine("Server exited."); // Wait for the client to exit. clientTask.GetAwaiter().GetResult(); }
public ValueTask <T?> GetProxyAsync <T>(ServiceRpcDescriptor descriptor, ServiceActivationOptions options, CancellationToken cancellationToken) where T : class { var pipePair = FullDuplexStream.CreatePipePair(); var clientConnection = descriptor .WithTraceSource(_services.ServiceProvider.TraceSource) .ConstructRpcConnection(pipePair.Item2); Contract.ThrowIfFalse(options.ClientRpcTarget is null == descriptor.ClientInterface is null); if (descriptor.ClientInterface != null) { Contract.ThrowIfNull(options.ClientRpcTarget); clientConnection.AddLocalRpcTarget(options.ClientRpcTarget); } // Clear RPC target so that the server connection is forced to create a new proxy for the callback // instead of just invoking the callback object directly (this emulates the product that does // not serialize the callback object over). options.ClientRpcTarget = null; // Creates service instance and connects it to the pipe. // We don't need to store the instance anywhere. _ = _services.CreateBrokeredService(descriptor, pipePair.Item1, options); clientConnection.StartListening(); return(ValueTaskFactory.FromResult((T?)clientConnection.ConstructRpcClient <T>())); }
public async Task InvokeWithPipe_ServerMethodDoesNotExist_ChannelOfferCanceled() { int?channelIdOffered = null; this.serverMx.ChannelOffered += (s, e) => { channelIdOffered = e.Id; }; (IDuplexPipe, IDuplexPipe)duplexPipes = FullDuplexStream.CreatePipePair(); await Assert.ThrowsAsync <RemoteMethodNotFoundException>(() => this.clientRpc.InvokeWithCancellationAsync("does not exist", new object[] { duplexPipes.Item2 }, this.TimeoutToken)); // By this point, the server has processed the server method, and the offer for a stream should have preceded that. Assert.True(channelIdOffered.HasValue); // In response to the server rejecting the RPC request, the client should have canceled the offer for the channel. // It may or may not have already occurred so for test stability, we code our assertion to handle both cases. try { MultiplexingStream.Channel serverChannel = this.serverMx.AcceptChannel(channelIdOffered !.Value); // The client had not yet canceled the offer. So wait for the client to close the channel now that we've accepted it. await serverChannel.Completion.WithCancellation(this.TimeoutToken); } catch (InvalidOperationException) { // The client had already canceled the offer. } }
public override async Task SeededChannels() { var pair = FullDuplexStream.CreatePair(); var options = new MultiplexingStream.Options { ProtocolMajorVersion = this.ProtocolMajorVersion, SeededChannels = { new MultiplexingStream.ChannelOptions { }, new MultiplexingStream.ChannelOptions { }, }, }; var mx1 = MultiplexingStream.Create(pair.Item1, options); var mx2 = MultiplexingStream.Create(pair.Item2, options); var channel1_0 = mx1.AcceptChannel(0); var channel1_1 = mx1.AcceptChannel(1); var channel2_0 = mx2.AcceptChannel(0); var channel2_1 = mx2.AcceptChannel(1); await this.TransmitAndVerifyAsync(channel1_0.AsStream(), channel2_0.AsStream(), new byte[] { 1, 2, 3 }); await this.TransmitAndVerifyAsync(channel1_1.AsStream(), channel2_1.AsStream(), new byte[] { 4, 5, 6 }); }
public async Task ClientCanSendReadOnlyPipeToServer(bool orderedArguments) { (IDuplexPipe, IDuplexPipe)pipes = FullDuplexStream.CreatePipePair(); pipes.Item1.Input.Complete(); // Indicate that this is only for the server to read -- not write to us. await pipes.Item1.Output.WriteAsync(MemoryBuffer, this.TimeoutToken); pipes.Item1.Output.Complete(); int bytesReceived; if (orderedArguments) { bytesReceived = await this.clientRpc.InvokeWithCancellationAsync <int>( nameof(Server.AcceptReadablePipe), new object[] { ExpectedFileName, pipes.Item2 }, this.TimeoutToken); } else { bytesReceived = await this.clientRpc.InvokeWithParameterObjectAsync <int>( nameof(Server.AcceptReadablePipe), new { fileName = ExpectedFileName, content = pipes.Item2 }, this.TimeoutToken); } Assert.Equal(MemoryBuffer.Length, bytesReceived); }
public async Task UsePipe_Stream_WriteOnlyStream() { var streamPair = FullDuplexStream.CreatePair(); var writeOnlyStream = new OneWayStreamWrapper(streamPair.Item1, canWrite: true); var duplexPipe = writeOnlyStream.UsePipe(); // Verify that reading isn't allowed. await Assert.ThrowsAsync <InvalidOperationException>(async() => await duplexPipe.Input.ReadAsync(this.TimeoutToken)); byte[] expected = new byte[] { 1, 2, 3 }; await duplexPipe.Output.WriteAsync(expected, this.TimeoutToken); duplexPipe.Output.Complete(); int totalBytesRead = 0; byte[] readBytes = new byte[10]; int bytesRead; do { bytesRead = await streamPair.Item2.ReadAsync(readBytes, totalBytesRead, readBytes.Length - totalBytesRead, this.TimeoutToken); this.Logger.WriteLine("Read {0} bytes", bytesRead); totalBytesRead += bytesRead; }while (bytesRead > 0); Assert.Equal(expected, readBytes.Take(totalBytesRead)); // Complete writing and verify stream closed. duplexPipe.Output.Complete(); await this.AssertStreamClosesAsync(streamPair.Item1); }
private Task <TestLspServer> CreateTsTestLspServerAsync(string workspaceXml) { var(clientStream, serverStream) = FullDuplexStream.CreatePair(); var testWorkspace = TestWorkspace.Create(workspaceXml, composition: Composition); var languageServerTarget = CreateLanguageServer(serverStream, serverStream, testWorkspace); return(TestLspServer.CreateAsync(testWorkspace, new ClientCapabilities(), languageServerTarget, clientStream)); }
public void TestRemoteHostCreation() { var remoteLogger = new TraceSource("inprocRemoteClient"); var testData = new RemoteHostTestData(new RemoteWorkspaceManager(new SolutionAssetCache()), isInProc: true); var streams = FullDuplexStream.CreatePair(); using var _ = new RemoteHostService(streams.Item1, new InProcRemoteHostClient.ServiceProvider(remoteLogger, testData)); }
public async Task SendPipeWithoutMultiplexingStream() { (Stream, Stream)streamPair = FullDuplexStream.CreatePair(); var clientRpc = JsonRpc.Attach(streamPair.Item1); (IDuplexPipe, IDuplexPipe)somePipe = FullDuplexStream.CreatePipePair(); await Assert.ThrowsAsync <NotSupportedException>(() => clientRpc.InvokeWithCancellationAsync(nameof(Server.TwoWayPipeAsArg), new[] { somePipe.Item2 }, this.TimeoutToken)); }
private static async Task Main(string[] args) { ////System.Diagnostics.Debugger.Launch(); var mx = await MultiplexingStream.CreateAsync(FullDuplexStream.Splice(Console.OpenStandardInput(), Console.OpenStandardOutput())); var program = new Program(mx); await program.RunAsync(); }
public void Attach_NonGeneric() { var streams = FullDuplexStream.CreateStreams(); var rpc = new JsonRpc(streams.Item1); var clientRpc = (IServerDerived)rpc.Attach(typeof(IServerDerived)); Assert.IsType(this.clientRpc.GetType(), clientRpc); }
public Task <Connection> ActivateAsync(CancellationToken token) { Contract.ThrowIfFalse(_languageServer == null, "This language server has already been initialized"); var(clientStream, serverStream) = FullDuplexStream.CreatePair(); _languageServer = new InProcLanguageServer(serverStream, serverStream, _languageServerProtocol, _workspace, _diagnosticService, clientName: _diagnosticsClientName, SupportsHover); return(Task.FromResult(new Connection(clientStream, clientStream))); }
public async Task ValueTaskReturningMethod() { var streams = FullDuplexStream.CreateStreams(); var server = new Server(); var serverRpc = JsonRpc.Attach(streams.Item2, server); var clientRpc = JsonRpc.Attach <IServerWithValueTasks>(streams.Item1); await clientRpc.DoSomethingValueAsync(); }
public void UsePipe_CollapseAdapterStacks() { var pipes = FullDuplexStream.CreatePipePair(); var stream = pipes.Item1.AsStream(); var pipeAgain = stream.UsePipe(allowUnwrap: true); Assert.Same(pipes.Item1.Input, pipeAgain.Input); Assert.Same(pipes.Item1.Output, pipeAgain.Output); }