lundi 31 août 2015

NODEJS [electron io.js] send input to spawned process child.stdin.write();

I have a set of scripts in PowerShell. I built a GUI with a .HTA, but I am migrating over to a NODE.js like approach.

I have a working script, but I had to make a modification to work around the lost functionality to get input from the command line. I used to have the CMD prompt window appear where I would see all output and, if there was a prompt (Read-Host), the user could interact with it. To work around that, I am now using [Microsoft.VisualBasic.Interaction]::InputBox() to get input from the user when needed.

I have had issues trying to use child.stdin.write(); because my PowerShell process just hangs. It will not respond to my input.

I have tried every answer I have found on the net, with no success. The script that is called in production is a long running process, depending on the task selected it will take from 20 min to 3 hours.

So, issue is I cannot get the child.spawned process to send the input, or maybe PowerShell does not accept input from sdin.

Thanks for your help in advance.

CODE:

HTML:

<button type="button" id="btn_ExecuteReport">Run Report</button>
<button type="button" id="btn_StopReport" >Stop Report</button>
<button type="button" id="btn_SendInput" >Send this...</button>
<h2>Results:</h2>
<p id="result_id">...</p>
<br/>

JS (using Electron v 0.31.0, io.js v 3.1.0, jQuery v 1.7.2):

$(document).ready(function () {
    $("#btn_ExecuteReport").click(function (event) {
        event.stopPropagation();
        global.$ = $;

        var remote = require('remote');
        // to get some paths depending on OS
        var app = remote.require('app');
        //clipboard
        var clipboard = require('clipboard');
        var shell = require('shell');
        // for choosing a folder
        var dialog = remote.require('dialog');
        var spawn = require('child_process').spawn;
        sCmd = "powershell.exe ";
        sCmdArg = '&' + "'" + __dirname + "/app.ps1' " ;
        // omit parameters for the purpose of this example
        //    + "-ODir '" + sOutputDirectory 
        //    + "' -WDir '" + sWorkingDirectory + "'" 
        //    + " -Report " + sReport 
        //    + " -pSendEmail " + sSendEmail 
        //    + " -pSendEmailHTMLBody " + sSendEmailHTMLBody 
        //    + " -pCreateReport " + sCreateReport 
        //    + " -pCheckReport " + sCheckReport 
        //    + " -pEmailAction " + sEmailAction
        //    ;
        $("#result_id").html("<p><font color='magenta'>Command: </font>" 
                                          + sCmdConcat + "</p>");
        // try again with spawn and event handlers
        var psSpawn = spawn(sCmd, [sCmdArg]);
        // add a 'data' event listener for the spawn instance
        psSpawn.stdout.on('data', function(data) { 
            console.log('stdout: ' + data); 
        });
        // add an 'end' event listener to close the writeable stream
        psSpawn.stdout.on('end', function(data) {
            console.log('Done with psSpawn...' );
        });
        psSpawn.stderr.on('data', function (data) {
            console.log('stderr: ' + data);
        });
        // when the spawn child process exits, check if there were any errors and close the writeable stream
        psSpawn.on('exit', function(code) {
            if (code != 0) {
                console.log('[EXIT] Failed: ' + code);
            }
            //Collect result from PowerShell (via clipboard)
            sResultData = clipboard.readText("Text");
        });

        psSpawn.on('close', function(code) {
            if (code != 0) {
                console.log('[ISSUE] code: ' + code);
            }
            console.log('[CLOSE]');
        });
        //sending the input with button #btn_sendInput
        $("#btn_SendInput").click(function (event) {
            psSpawn.stdin.setEncoding('utf8');
            psSpawn.stdin.write('ok');
            psSpawn.stdin.write('\n');
            psSpawn.stdin.write(os.EOL);
            //uncomment following line to end stdin on first button press
            //psSpawn.stdin.end();
        });

        // killing process
        $("#btn_StopReport").click(function (event) {
            event.stopPropagation();
            psSpawn.kill('SIGTERM');
            console.log('killed ' + psSpawn.pid);
        });
    });
});

PowerShell:

#work around to lack of Read-Host functionality
Write-Host "waiting"
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null
$computer = [Microsoft.VisualBasic.Interaction]::InputBox("Enter a computer name", "Computer", "$env:computername") 
#
Write-Host "[Done] waiting"
#workaround END works 
Write-Host "Computer: [$computer]"
# START omit ----------------
#if we remove the following lines, all works but we lose the functionality to ask for input from the command line
Write-Host "Propmt for OK" 
$ok = Read-Host 
#
Write-Host "Prompt. Value of 'ok': [$ok]"
# END omit ----------------
#Copy new message to clipboard
"we want to see this maessage on the browser. $computer" | clip

#Exit script returning the appropriate value
[Environment]::Exit(0)
exit

My console output is:

stdout: waiting
daily_deviation.js:103 stdout: 

daily_deviation.js:103 stdout: [Done] waiting
Computer: [0199HR10A]
Propmt for OK

The script hands no matter how many times I press Send this.... The console output is (after pressing the #buton_StopReport):

killed 2548
daily_deviation.js:107 Done with psSpawn...
daily_deviation.js:115 [EXIT] Failed: null
daily_deviation.js:140 [ISSUE] code: null
daily_deviation.js:142 [CLOSE]



via Chebli Mohamed

Aucun commentaire:

Enregistrer un commentaire