Javascript.NodeJS icon indicating copy to clipboard operation
Javascript.NodeJS copied to clipboard

How to pass stdio to nodejs

Open soroshsabz opened this issue 3 years ago • 12 comments

ITNOA

I want to link my stdio from C# Console Application to NodeJs, to better describe my question, I create a sample like below

I have some code like below

            IJsEngine engine = new NodeJsEngine(new NodeSettings { UseBuiltinLibrary = true});
            engine.ExecuteFile("SpawnServer.js");

and my SpawnServer.js is like below

const { spawn } = require("child_process");

console.log('Hi');
process.stdout.write("Hi");
spawn("npx", ["ansible-language-server"].concat(" --stdio"), { stdio: 'inherit' });

I like to see Hi in my C# Console Application, But I do not know, How to do it?

Note: All code is in https://github.com/soroshsabz/visualstudio-ansible/tree/features/4-support-ansible-language-server

thanks

soroshsabz avatar Mar 21 '23 22:03 soroshsabz

I add this question in SO

soroshsabz avatar Mar 21 '23 22:03 soroshsabz

@Taritsyn Did you have any idea?

soroshsabz avatar Mar 23 '23 08:03 soroshsabz

related to https://github.com/Taritsyn/JavaScriptEngineSwitcher/issues/110

soroshsabz avatar Mar 23 '23 09:03 soroshsabz

@JeremyTCD Did you have any Idea? or if this library does not support this, Did you have any advice to how to add this feature? maybe I can provide PR for this

soroshsabz avatar Mar 23 '23 09:03 soroshsabz

Hey apologies for the slow response, I'm not sure how to pipe output when using JavaScriptEngineSwitcher, but if you use this library directly, you can do it like this:

using Jering.Javascript.NodeJS;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Example.Logging
{
    internal class Program
    {
        static async Task Main(string[] _)
        {
            // Prepare DI services
            var serviceCollection = new ServiceCollection();
            serviceCollection.AddNodeJS();
            serviceCollection.AddLogging((ILoggingBuilder loggingBuilder) =>
            {
                loggingBuilder.AddConsole();
            });

            // Get INodeJSService
            IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
            INodeJSService nodeJSService = serviceProvider.GetRequiredService<INodeJSService>();

            // Invoke js
            await nodeJSService.InvokeFromStringAsync(@"module.exports = (callback) => { 
    console.log('Hello world!'); 
    callback(null); 
}").ConfigureAwait(false);
        }
    }
}

Your project will have to reference the Jering.Javascript.NodeJS and Microsoft.Extensions.Logging.Console packages.

You will get output like:

info: Jering.Javascript.NodeJS.HttpNodeJSService[0]
      Connected to NodeJS through HTTP/1.1. Endpoint: http://[::1]:62220/.
info: Jering.Javascript.NodeJS.HttpNodeJSService[0]
      Connected to NodeJS process: 11960.
info: System.Net.Http.HttpClient.IHttpClientService.LogicalHandler[100]
      Start processing HTTP request POST http://[::1]:62220/
info: System.Net.Http.HttpClient.IHttpClientService.ClientHandler[100]
      Sending HTTP request POST http://[::1]:62220/
info: Jering.Javascript.NodeJS.HttpNodeJSService[0]
      Hello world!
info: System.Net.Http.HttpClient.IHttpClientService.ClientHandler[101]
      Received HTTP response headers after 101.8191ms - 200
info: System.Net.Http.HttpClient.IHttpClientService.LogicalHandler[101]
      End processing HTTP request after 108.5691ms - 200

You can filter output by following Microsoft's instructions here.

Let me know if you have any issues.

JeremyTCD avatar Mar 25 '23 06:03 JeremyTCD

@JeremyTCD are you sure, this method, redirect standard I/O to/from NodeJS, for example, what is happen, if I run below code in the NodeJS

const stdin = process.openStdin()

process.stdout.write('Enter name: ')

stdin.addListener('data', text => {
  const name = text.toString().trim()
  console.log('Your name is: ' + name)

  stdin.pause() // stop reading
})

Are you sure, nodeJs get input from my standard input?

thanks

soroshsabz avatar Mar 26 '23 03:03 soroshsabz

Ah it does not.

I assumed from your "hi" example that you just needed output, stdin is not piped from .Net to Node.js.

Would an invocation work? E.g.

string? data = Console.ReadLine();
nodeJSService.InvokeFromStringAsync(..., args: new object?[] { data });

JeremyTCD avatar Mar 27 '23 05:03 JeremyTCD

@JeremyTCD No, I want to bind (redirect) all input and output together, from/to .Net Node.js. for example, I have console application in Node.JS and I want when run this app in .Net, user can seamless using this app.

thanks

soroshsabz avatar Mar 27 '23 12:03 soroshsabz

Options:

  • Use invocations to "pipe" input to the Node.js process.
  • Register a custom service for INodeJSProcessFactory that pipes input to the Node.js process.

JeremyTCD avatar Mar 27 '23 12:03 JeremyTCD

I do not understand, did you can provide some example? (If I understand correctly, you says Jering can support redirection both standard output and input? correct?)

soroshsabz avatar Mar 27 '23 12:03 soroshsabz

Piping input to Node.js processes is not supported out-of-the-box. But there are ways to implement such behaviour.

For the first option, read input and pass it to the Node.js process using invocations, like in this comment.

As for the second option, replace the INodeJSProcessFactory service that creates Node.js processes with a custom one that pipes input to them. Replacement of the service is done using standard Microsoft DI patterns. You can use the existing service to get started on your custom implementation. Microsoft has an example on piping to a process' stdin.

JeremyTCD avatar Mar 27 '23 12:03 JeremyTCD