2015-03-30 8 views
7

Sfondo

Sto lavorando a un programma C# che esegue attualmente il nodo tramite Process.Start(). Sto catturando lo stdout e lo stderr da questo processo figlio e reindirizzandolo per le mie ragioni. Sto cercando di sostituire l'invocazione di Node.exe con una chiamata a Edge.js invece. Per essere in grado di farlo, devo essere in grado di catturare in modo affidabile stdout e stderr dal Javascript in esecuzione in Edge e recuperare i messaggi nella mia applicazione C#.Quando si chiama Edge.js da C#, come si agganciano lo stdout e lo stderr?

Approccio 1

io descrivere questo approccio per completezza in caso qualcuno lo consiglia :)

Se il processo termina bordo, è abbastanza facile da affrontare questo semplicemente dichiarando un array di msgs e sovrascrivendo process.stdout.write e process.stderr.write con nuove funzioni che accumulano messaggi su tale array, quindi alla fine, è sufficiente restituire l'array msgs. Esempio:

var msgs = []; 
process.stdout.write = function (string) { 
    msgs.push({ stream: 'o', message : string }); 
}; 
process.stderr.write = function (string) { 
    msgs.push({ stream: 'e', message: string }); 
}; 

// Return to caller. 
var result = { messages: msgs; ...other stuff... }; 
callback(null, result); 

Ovviamente questo funziona solo se il codice bordo termina, e msg possa crescere di grandi dimensioni nel peggiore dei casi. Tuttavia, è probabile che funzioni bene perché è necessaria una sola chiamata di marshalling per recuperare tutti i messaggi.

Approccio 2

Questo è un po 'più difficile da spiegare. Invece di accumulare messaggi, "agganciamo" lo stdout e lo stderr usando un delegato che inviamo da C#. In C#, creiamo un oggetto che passeremo in bordo, e che oggetto ha una proprietà chiamata stdoutHook:

dynamic payload = new ExpandoObject(); 
payload.stdoutHook = GetStdoutHook(); 

public Func<object, Task<object>> GetStdoutHook() 
{ 
    Func<object, Task<object>> hook = (message) => 
    { 
     TheLogger.LogMessage((message as string).Trim()); 
     return Task.FromResult<object>(null); 
    }; 

    return hook; 
} 

ho potuto realmente ottenere via con un'azione, ma Bordo sembra richiedere l'Func<object, Task<object>>, ha vinto 's proxy la funzione in caso contrario. Poi, nel Javascript, siamo in grado di rilevare che la funzione e usarlo in questo modo:

var func = Edge.Func(@" 
    return function(payload, callback) { 
     if (typeof (payload.stdoutHook) === 'function') { 
      process.stdout.write = payload.stdoutHook; 
     } 

     // do lots of stuff while stdout and stderr are hooked... 
     var what = require('whatever'); 
     what.futz(); 

     // terminate. 
     callback(null, result); 
}"); 

dynamic result = func(payload).Result; 

Domande

Q1. Entrambe queste tecniche sembrano funzionare, ma c'è un modo migliore di farlo, qualcosa di integrato a Edge forse che mi è sfuggito? Entrambe le soluzioni sono invasive: richiedono un certo codice di shim per avvolgere il lavoro effettivo che deve essere svolto in Edge. Questa non è la fine del mondo, ma sarebbe meglio se esistesse un metodo non invasivo.

Q2. Nel metodo 2, dove devo restituire un compito qui

return Task.FromResult<object>(null); 

si sente sbagliato essere la restituzione di un già completato "compito nullo". Ma c'è un altro modo di scrivere questo?

Q3. Devo essere più rigoroso nel codice Javascript durante l'aggancio di stdout e stderr? Prendo atto in doppio-edge.js c'è questo codice, francamente non sono sicuro di quello che sta succedendo qui, ma è un po 'più complessa di quanto la mia sovrascrittura cruda :-) process.stdout.write

// Fix #176 for GUI applications on Windows 
try { 
    var stdout = process.stdout; 
} 
catch (e) { 
    // This is a Windows GUI application without stdout and stderr defined. 
    // Define process.stdout and process.stderr so that all output is discarded. 
    (function() { 
     var stream = require('stream'); 
     var NullStream = function (o) { 
      stream.Writable.call(this); 
      this._write = function (c, e, cb) { cb && cb(); }; 
     } 
     require('util').inherits(NullStream, stream.Writable); 
     var nullStream = new NullStream(); 
     process.__defineGetter__('stdout', function() { return nullStream; }); 
     process.__defineGetter__('stderr', function() { return nullStream; }); 
    })(); 
} 

risposta

2

D1: Non c'è nulla di integrato in Edge che renderebbe automaticamente l'acquisizione di stdout o stderr del codice Node.js quando si chiama Node da CLR. Ad un certo punto ho pensato di scrivere un'estensione di Edge che avrebbe reso facile il marshalling dei flussi attraverso il confine CLR/V8. Sotto il cofano sarebbe molto simile al tuo approccio 2.Potrebbe essere fatto come un modulo standalone in cima a Edge.

Q2: restituire un'attività completata è molto appropriato in questo caso. La tua funzione ha catturato l'output Node.js, l'ha elaborata e in effetti ha "completato" in questo senso. Restituire un'attività completata con Null è in realtà un equivalente morale del ritorno da un'azione.

Q3: il codice che si sta indicando è rilevante solo nelle applicazioni GUI di Windows, non nelle applicazioni della console. Se stai scrivendo un'applicazione Console, è sufficiente sostituire il codice write a livello del codice Node.js che passi a Edge.js. Si noti che la firma di write nel nodo consente un encoding parameter to be passed in opzionale. Sembra che tu lo ignori entrambi in Approach 1 e 2. In particolare in Approach 2 suggerirei di avvolgere il proxy JavaScript in C# callback in una funzione JavaScript che normalizzi i parametri prima di assegnarli a process.stdout.write. In caso contrario, il codice Edge.js può presupporre che il parametro encoding passato a una chiamata write sia una funzione di callback che seguirebbe la convenzione di chiamata Edge.js.

+0

Grazie Tomasz, quindi fondamentalmente l'approccio 2 con attenzione alla codifica è la mia migliore scommessa per ora. Sarebbe bello se ci fosse un modo più semplice per farlo, forse un sovraccarico di Edge.Func() che può richiedere un paio di stream o delegati opzionali. –

Problemi correlati