Files
JavaScriptServices/Microsoft.AspNet.NodeServices/HostingModels/InputOutputStreamNodeHost.cs
SteveSandersonMS f693bd60e3 Initial state
2015-11-02 10:30:36 -08:00

58 lines
2.7 KiB
C#

using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace Microsoft.AspNet.NodeServices {
// This is just to demonstrate that other transports are possible. This implementation is extremely
// dubious - if the Node-side code fails to conform to the expected protocol in any way (e.g., has an
// error), then it will just hang forever. So don't use this.
//
// But it's fast - the communication round-trip time is about 0.2ms (tested on OS X on a recent machine),
// versus 2-3ms for the HTTP transport.
//
// Instead of directly using stdin/stdout, we could use either regular sockets (TCP) or use named pipes
// on Windows and domain sockets on Linux / OS X, but either way would need a system for framing the
// requests, associating them with responses, and scheduling use of the comms channel.
internal class InputOutputStreamNodeHost : OutOfProcessNodeRunner
{
private SemaphoreSlim _invocationSemaphore = new SemaphoreSlim(1);
private TaskCompletionSource<string> _currentInvocationResult;
private readonly static JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings {
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
public InputOutputStreamNodeHost()
: base(EmbeddedResourceReader.Read(typeof(InputOutputStreamNodeHost), "/Content/Node/entrypoint-stream.js"))
{
}
public override async Task<string> Invoke(NodeInvocationInfo invocationInfo) {
await this._invocationSemaphore.WaitAsync();
try {
await this.EnsureReady();
var payloadJson = JsonConvert.SerializeObject(invocationInfo, jsonSerializerSettings);
var nodeProcess = this.NodeProcess;
this._currentInvocationResult = new TaskCompletionSource<string>();
nodeProcess.StandardInput.Write("\ninvoke:");
nodeProcess.StandardInput.WriteLine(payloadJson); // WriteLineAsync isn't supported cross-platform
return await this._currentInvocationResult.Task;
} finally {
this._invocationSemaphore.Release();
this._currentInvocationResult = null;
}
}
protected override void OnOutputDataReceived(string outputData) {
if (this._currentInvocationResult != null) {
this._currentInvocationResult.SetResult(outputData);
} else {
base.OnOutputDataReceived(outputData);
}
}
}
}