从 C# 调用 Edge.js 时,如何挂接 stdout 和 stderr?
When calling Edge.js from C#, how do you hook stdout and stderr?
背景
我正在开发一个 C# 程序,该程序当前通过 Process.Start() 运行 Node。我正在从这个子进程中捕获 stdout 和 stderr,并出于我自己的原因将其重定向。我正在考虑将 Node.exe 的调用替换为对 Edge.js 的调用。为了能够做到这一点,我必须能够从 Edge 中的 Javascript 运行 可靠地捕获 stdout 和 stderr,并将消息返回到我的 C# 应用程序中。
方法一
我会完整地描述这种方法,以防有人推荐它:)
如果 Edge 进程终止,通过简单地声明一个 msgs
数组并用在其上累积消息的新函数覆盖 process.stdout.write
和 process.stderr.write
来处理这个问题相当容易数组,然后在最后,简单地 return msgs
数组。示例:
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);
显然这仅在 Edge 代码终止时有效,并且在最坏的情况下消息可能会变大。但是,它可能会执行良好,因为只需要一个编组调用就可以返回所有消息。
方法二
这有点难以解释。我们 "hook" stdout 和 stderr 使用从 C# 发送的委托,而不是累积消息。在 C# 中,我们创建一个将传递给 Edge 的对象,该对象有一个名为 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;
}
我真的可以通过 Action 逃脱,但 Edge 似乎需要 Func<object, Task<object>>
,否则它不会代理该功能。然后,在 Javascript 中,我们可以检测到该函数并像这样使用它:
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;
问题
Q1。这两种技术似乎都有效,但是否有更好的方法来做到这一点,也许我错过了 Edge 内置的东西?这两种解决方案都是侵入性的——它们需要一些垫片代码来包装要在 Edge 中完成的实际工作。这不是世界末日,但如果有一种非侵入性的方法就更好了。
Q2。在方法 2 中,我必须 return 这里的任务
return Task.FromResult<object>(null);
感觉 return 已经完成 "null task" 是不对的。但是还有其他的写法吗?
Q3。挂钩 stdout 和 stderr 时,我是否需要在 Javascript 代码中更加严格?我注意到在 double-edge.js 中有这段代码,坦率地说,我不确定这里发生了什么,但它比我粗略地覆盖 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; });
})();
}
Q1:从 CLR 调用 Node 时,Edge 中没有内置任何东西可以自动捕获 Node.js 代码的 stdout 或 stderr。在某些时候,我想到编写 Edge 的扩展,这将使跨 CLR/V8 边界的流编组变得容易。在引擎盖下,它与您的方法 2 非常相似。它可以作为 Edge 之上的独立模块来完成。
Q2:返回一个完成的任务在这种情况下是非常合适的。您的函数捕获了 Node.js 输出,对其进行了处理,并且实际上 "completed" 在这个意义上。返回以 Null 完成的任务在道德上等同于从 Action 返回。
Q3:您指向的代码仅与 Windows GUI 应用程序相关,与控制台应用程序无关。如果您正在编写控制台应用程序,只需覆盖 write
就足以满足您传递给 Edge.js 的 Node.js 代码级别。请注意,Node 中 write
的签名允许可选的 encoding parameter to be passed in。您似乎在方法 1 和方法 2 中都忽略了它。特别是在方法 2 中,我建议将 JavaScript 代理包装到 C# 回调到 JavaScript 函数中,该函数在将参数分配给 [=12 之前规范化参数=].否则 Edge.js 代码可能假定传递给 write
调用的 encoding
参数是一个回调函数,它遵循 Edge.js 调用约定。
背景
我正在开发一个 C# 程序,该程序当前通过 Process.Start() 运行 Node。我正在从这个子进程中捕获 stdout 和 stderr,并出于我自己的原因将其重定向。我正在考虑将 Node.exe 的调用替换为对 Edge.js 的调用。为了能够做到这一点,我必须能够从 Edge 中的 Javascript 运行 可靠地捕获 stdout 和 stderr,并将消息返回到我的 C# 应用程序中。
方法一
我会完整地描述这种方法,以防有人推荐它:)
如果 Edge 进程终止,通过简单地声明一个 msgs
数组并用在其上累积消息的新函数覆盖 process.stdout.write
和 process.stderr.write
来处理这个问题相当容易数组,然后在最后,简单地 return msgs
数组。示例:
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);
显然这仅在 Edge 代码终止时有效,并且在最坏的情况下消息可能会变大。但是,它可能会执行良好,因为只需要一个编组调用就可以返回所有消息。
方法二
这有点难以解释。我们 "hook" stdout 和 stderr 使用从 C# 发送的委托,而不是累积消息。在 C# 中,我们创建一个将传递给 Edge 的对象,该对象有一个名为 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;
}
我真的可以通过 Action 逃脱,但 Edge 似乎需要 Func<object, Task<object>>
,否则它不会代理该功能。然后,在 Javascript 中,我们可以检测到该函数并像这样使用它:
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;
问题
Q1。这两种技术似乎都有效,但是否有更好的方法来做到这一点,也许我错过了 Edge 内置的东西?这两种解决方案都是侵入性的——它们需要一些垫片代码来包装要在 Edge 中完成的实际工作。这不是世界末日,但如果有一种非侵入性的方法就更好了。
Q2。在方法 2 中,我必须 return 这里的任务
return Task.FromResult<object>(null);
感觉 return 已经完成 "null task" 是不对的。但是还有其他的写法吗?
Q3。挂钩 stdout 和 stderr 时,我是否需要在 Javascript 代码中更加严格?我注意到在 double-edge.js 中有这段代码,坦率地说,我不确定这里发生了什么,但它比我粗略地覆盖 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; });
})();
}
Q1:从 CLR 调用 Node 时,Edge 中没有内置任何东西可以自动捕获 Node.js 代码的 stdout 或 stderr。在某些时候,我想到编写 Edge 的扩展,这将使跨 CLR/V8 边界的流编组变得容易。在引擎盖下,它与您的方法 2 非常相似。它可以作为 Edge 之上的独立模块来完成。
Q2:返回一个完成的任务在这种情况下是非常合适的。您的函数捕获了 Node.js 输出,对其进行了处理,并且实际上 "completed" 在这个意义上。返回以 Null 完成的任务在道德上等同于从 Action 返回。
Q3:您指向的代码仅与 Windows GUI 应用程序相关,与控制台应用程序无关。如果您正在编写控制台应用程序,只需覆盖 write
就足以满足您传递给 Edge.js 的 Node.js 代码级别。请注意,Node 中 write
的签名允许可选的 encoding parameter to be passed in。您似乎在方法 1 和方法 2 中都忽略了它。特别是在方法 2 中,我建议将 JavaScript 代理包装到 C# 回调到 JavaScript 函数中,该函数在将参数分配给 [=12 之前规范化参数=].否则 Edge.js 代码可能假定传递给 write
调用的 encoding
参数是一个回调函数,它遵循 Edge.js 调用约定。