I’ve managed to get it working using the following code snippets. I’m considering writing a package to simplify this process - do you think it’d be useful?
Console = new Mongo.Collection('console');
if (Meteor.isServer) {
exec = Npm.require('child_process').exec;
Fiber = Npm.require('fibers');
_execSync = function(cmd, stdoutHandler, stderrHandler) {
exec(cmd, Meteor.bindEnvironment(
function(error, stdout, stderr) {
if (stdout != "")
stdoutHandler(stdout);
if (stderr != "")
stderrHandler(stderr);
}
)
);
}
Meteor.methods({
consoleExecSync : function(cmd) {
_execSync(cmd, consoleInsert, consoleInsert);
}
});
consoleInsert = function(_data) {
Console.insert({
timestamp : new Date().getTime(),
data : _data
});
}
}
Basically, the way I do it is I pass a “stdoutHandler” and “stderrHandler” to the _execSync function, which then calls the handlers any time the stdout or stderr is flushed. It’s important to note that some programs do a very poor job of flushing the pipe. If the thing you are exec’ing is a python script, for example, you need to explicitly call sys.stdout.flush() in order for this to work (print does not do it by default).
The consoleInsert function here just takes the data and inserts it into a collection. In my application, I have a “console” that I have a {{#each console}} template in that displays the console documents to the client. This results in pretty close to live output from the exec’d program.
Does that help?