protected override Task <T> InvokeExportAsync <T>( NodeInvocationInfo invocationInfo, CancellationToken cancellationToken) { return(Task.FromResult <T>(default(T))); //throw new NotImplementedException("Use overloaded Invoke method instead"); }
protected override async Task <T> InvokeExportAsync <T>( NodeInvocationInfo invocationInfo, CancellationToken cancellationToken) { var payloadJson = JsonConvert.SerializeObject(invocationInfo, jsonSerializerSettings); var payload = new StringContent(payloadJson, Encoding.UTF8, "application/json"); var watch = new Stopwatch(); watch.Start(); var response = await _client.PostAsync(_endpoint, payload, cancellationToken); watch.Stop(); Trace.WriteLine($"Node call: {watch.ElapsedTicks}"); if (!response.IsSuccessStatusCode) { // Unfortunately there's no true way to cancel ReadAsStringAsync calls, hence AbandonIfCancelled var responseJson = await response.Content.ReadAsStringAsync().OrThrowOnCancellation(cancellationToken); var responseError = JsonConvert.DeserializeObject <RpcJsonResponse>(responseJson, jsonSerializerSettings); throw new NodeInvocationException(responseError.ErrorMessage, responseError.ErrorDetails); } var responseContentType = response.Content.Headers.ContentType; switch (responseContentType.MediaType) { case "text/plain": // String responses can skip JSON encoding/decoding if (typeof(T) != typeof(string)) { throw new ArgumentException( "Node module responded with non-JSON string. This cannot be converted to the requested generic type: " + typeof(T).FullName); } var responseString = await response.Content.ReadAsStringAsync().OrThrowOnCancellation(cancellationToken); return((T)(object)responseString); case "application/json": var responseJson = await response.Content.ReadAsStringAsync().OrThrowOnCancellation(cancellationToken); return(JsonConvert.DeserializeObject <T>(responseJson, jsonSerializerSettings)); case "application/octet-stream": // Streamed responses have to be received as System.IO.Stream instances if (typeof(T) != typeof(Stream) && typeof(T) != typeof(object)) { throw new ArgumentException( "Node module responded with binary stream. This cannot be converted to the requested generic type: " + typeof(T).FullName + ". Instead you must use the generic type System.IO.Stream."); } return((T)(object)(await response.Content.ReadAsStreamAsync().OrThrowOnCancellation(cancellationToken))); default: throw new InvalidOperationException("Unexpected response content type: " + responseContentType.MediaType); } }
protected override async Task <T> InvokeExportAsync <T>(NodeInvocationInfo invocationInfo, CancellationToken cancellationToken) { if (_connectionHasFailed) { // _connectionHasFailed implies a protocol-level error. The old instance is no longer of any use. var allowConnectionDraining = false; // This special exception type forces NodeServicesImpl to restart the Node instance throw new NodeInvocationException( "The SocketNodeInstance socket connection failed. See logs to identify the reason.", details: null, nodeInstanceUnavailable: true, allowConnectionDraining: allowConnectionDraining); } if (_virtualConnectionClient == null) { // Although we could pass the cancellationToken into EnsureVirtualConnectionClientCreated and // have it signal cancellations upstream, that would be a bad thing to do, because all callers // wait for the same connection task. There's no reason why the first caller should have the // special ability to cancel the connection process in a way that would affect subsequent // callers. So, each caller just independently stops awaiting connection if that call is cancelled. await ThrowOnCancellation(EnsureVirtualConnectionClientCreated(), cancellationToken); } // For each invocation, we open a new virtual connection. This gives an API equivalent to opening a new // physical connection to the child process, but without the overhead of doing so, because it's really // just multiplexed into the existing physical connection stream. bool shouldDisposeVirtualConnection = true; Stream virtualConnection = null; try { virtualConnection = _virtualConnectionClient.OpenVirtualConnection(); // Send request WriteJsonLine(virtualConnection, invocationInfo); // Determine what kind of response format is expected if (typeof(T) == typeof(Stream)) { // Pass through streamed binary response // It is up to the consumer to dispose this stream, so don't do so here shouldDisposeVirtualConnection = false; return((T)(object)virtualConnection); } else { // Parse and return non-streamed JSON response var response = await ReadJsonAsync <RpcJsonResponse <T> >(virtualConnection, cancellationToken); if (response.ErrorMessage != null) { throw new NodeInvocationException(response.ErrorMessage, response.ErrorDetails); } return(response.Result); } } finally { if (shouldDisposeVirtualConnection) { virtualConnection.Dispose(); } } }
protected override Task <T> InvokeExportAsync <T>( NodeInvocationInfo invocationInfo, CancellationToken cancellationToken) { return(Task.FromResult <T>(default(T))); }