196 lines
6.9 KiB
JavaScript
196 lines
6.9 KiB
JavaScript
const iconv = require('iconv-lite');
|
|
class childProcess {
|
|
/**
|
|
*
|
|
* @param {String|any} option
|
|
* @param {Function} messageCallback
|
|
* @param {Function} errorCallback
|
|
*/
|
|
constructor(option, messageCallback = null, errorCallback = null) {
|
|
this.childprocess = null;
|
|
this.onceListenters = {};
|
|
this.alawysListenters = {};
|
|
this.cachedata = "";
|
|
this.alwaysListenter = null;
|
|
this.errorListenter = null;
|
|
this.trueClose = false;
|
|
var me = this;
|
|
|
|
var defaultOpt = {
|
|
exe: 'NYSProcess.exe',
|
|
closeCallback: function (exitcode) { },
|
|
autoReOpen: false,
|
|
args: []
|
|
};
|
|
var opt = null;
|
|
if (typeof option == 'string') {
|
|
defaultOpt.exe = option;
|
|
opt = defaultOpt;
|
|
}
|
|
else {
|
|
var extend = require('util')._extend;
|
|
opt = extend(defaultOpt, option);
|
|
}
|
|
//opt.args = ['pos'].concat(opt.args);
|
|
function S4() {
|
|
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
|
};
|
|
|
|
this.guid = function () {
|
|
return (S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4());
|
|
};
|
|
|
|
function endsWith(str, suffix) {
|
|
return str.indexOf(suffix, str.length - suffix.length) !== -1;
|
|
}
|
|
|
|
/**
|
|
* 获取参数
|
|
* @param {any} obj
|
|
* @returns
|
|
*/
|
|
function buildParam(obj) {
|
|
return { cguid: me.guid(), data: obj };
|
|
}
|
|
|
|
// 打开程序进程
|
|
this.open = function () {
|
|
var exec = require("child_process").spawn;
|
|
|
|
me.childprocess = exec(opt.exe, opt.args);
|
|
if (me.childprocess == null) {
|
|
if (opt.closeCallback) {
|
|
throw new Error('启动进程失败');
|
|
}
|
|
}
|
|
// 设置标准的输入输出
|
|
me.childprocess.stdin.setEncoding("binary");
|
|
me.childprocess.stdout.setEncoding("binary");
|
|
// 监听进程退出事件
|
|
me.childprocess.on('exit', function (code) {
|
|
if (opt.autoReOpen && code != 0 && !me.trueClose) {
|
|
// 自动重启
|
|
setTimeout(function () {
|
|
me.open();
|
|
console.log('reopen' + opt.exe, !!me.childprocess);
|
|
}, 1000);
|
|
}
|
|
if (opt.closeCallback) {
|
|
opt.closeCallback(code)
|
|
}
|
|
});
|
|
// 监听程序得输出事件
|
|
me.childprocess.stdout.on('data', function (data) {
|
|
// convert charset
|
|
data = iconv.decode(data.toString(), 'gbk');
|
|
var result = null;
|
|
var json = '';
|
|
try {
|
|
// 获取输入内容
|
|
json = data.toString();
|
|
// console.log('process out:', json);
|
|
if (endsWith(json, '\r\n')) {
|
|
json = json.substr(0, json.length - 1);
|
|
}
|
|
json = me.cachedata + json;
|
|
me.cachedata = "";
|
|
let resultdatas = json.split('@=@');
|
|
// 解析数据对象
|
|
for (let j in resultdatas) {
|
|
if (resultdatas.length == 1) {
|
|
me.cachedata += resultdatas[j];
|
|
continue;
|
|
}
|
|
if (j == (resultdatas.length - 1) && resultdatas[j] != '') {
|
|
me.cachedata += resultdatas[j];
|
|
continue;
|
|
}
|
|
|
|
let jsondata = "";
|
|
try {
|
|
jsondata = JSON.parse(resultdatas[j]);
|
|
|
|
} catch (ee) {
|
|
me.cachedata += resultdatas[j];
|
|
continue;
|
|
}
|
|
// 对数据进行回调
|
|
if (me.onceListenters[jsondata.cguid]) {
|
|
|
|
// 回调
|
|
me.onceListenters[jsondata.cguid](jsondata.Error, jsondata.data);
|
|
// 删除回调
|
|
delete me.onceListenters[jsondata.cguid];
|
|
}
|
|
|
|
if (me.alawysListenters[jsondata.cguid]) {
|
|
me.alawysListenters[jsondata.cguid](jsondata.Error, jsondata.data);
|
|
}
|
|
|
|
if (me.alwaysListenter) {
|
|
me.alwaysListenter(jsondata.data, jsondata.Error);
|
|
}
|
|
if (me.errorListenter && jsondata.Error && jsondata.Error.length > 2) {
|
|
me.errorListenter(jsondata.Error);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
|
|
// 错误回调
|
|
if (me.errorListenter) {
|
|
me.errorListenter(e.message);
|
|
} else {
|
|
console.error(e);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
// 停止进程
|
|
this.close = function (close = true) {
|
|
me.trueClose = close;
|
|
me.childprocess.kill();
|
|
};
|
|
this.exit = function () {
|
|
me.trueClose = true;
|
|
me.childprocess.kill();
|
|
};
|
|
/**
|
|
* 发送数据,注意此方法只会响应一次
|
|
* @param {any} data 待发送数据
|
|
* @param {string} command 指令
|
|
*/
|
|
this.send = function (param, command = 'default') {
|
|
return new Promise((resolve, reject) => {
|
|
let error = null;
|
|
if (!me.childprocess) {
|
|
error = '所需进程尚未启动';
|
|
}
|
|
if (!me.childprocess.stdin.writable) {
|
|
error = '无法建立通道连接';
|
|
}
|
|
if (error) {
|
|
reject(new Error(error));
|
|
} else {
|
|
const data = buildParam({ command, param });
|
|
// console.log('==> send data:', JSON.stringify(data))
|
|
// 设置回调
|
|
me.onceListenters[data.cguid] = (err, data) => {
|
|
if (err) {
|
|
reject(new Error(err));
|
|
} else {
|
|
resolve(data)
|
|
}
|
|
};
|
|
// 写入数据
|
|
me.childprocess.stdin.write(iconv.encode(JSON.stringify(data) + "\r\n", 'gbk'));
|
|
}
|
|
});
|
|
};
|
|
|
|
me.alwaysListenter = messageCallback;
|
|
me.errorListenter = errorCallback;
|
|
me.open();
|
|
}
|
|
}
|
|
module.exports = childProcess; |