first commit
This commit is contained in:
commit
afbb62d536
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
exe
|
43
README.MD
Normal file
43
README.MD
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
## Installation
|
||||||
|
```
|
||||||
|
npm install git+https://git.wm-app.xyz/dev/csharp-process.git
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```
|
||||||
|
yarn add git+https://git.wm-app.xyz/dev/csharp-process.git
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
in C#
|
||||||
|
```cs
|
||||||
|
class Program : NodeProcess
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
NodeSharp.Start(new Program());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnAction(NodeParam param, RPCHandle rpc)
|
||||||
|
{
|
||||||
|
|
||||||
|
rpc.Send(" ==> test " + param.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
in node
|
||||||
|
```js
|
||||||
|
import Porcess from 'csharp-process'
|
||||||
|
|
||||||
|
const service = new Process('./demo.exe',result => {
|
||||||
|
console.log('result:',result)
|
||||||
|
},error => {
|
||||||
|
console.log('error:',error)
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await service.send('hello csharp', 'test');
|
||||||
|
console.log('process result:', result)
|
||||||
|
} catch (e) {
|
||||||
|
console.log('process Error:', e)
|
||||||
|
}
|
||||||
|
```
|
194
csharp-process.js
Normal file
194
csharp-process.js
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
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) {
|
||||||
|
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;
|
49
example.js
Normal file
49
example.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
const { setInterval } = require('timers');
|
||||||
|
const Process = require('./csharp-process');
|
||||||
|
|
||||||
|
//正常启动一个exe
|
||||||
|
// var exeservice=new childprocess('./exe/NodeSharpTest.exe');
|
||||||
|
// console.log(exeservice);
|
||||||
|
|
||||||
|
|
||||||
|
//高级启动
|
||||||
|
// var defaultOpt = {
|
||||||
|
// exe: 'NYSProcess.exe',//exe 路径
|
||||||
|
// closeCallback: function (exitcode) { },//exe退出的回调
|
||||||
|
// autoReOpen: false,//是否自动启动(如exe异常终止后可以自动重启)
|
||||||
|
// args: []//给exe的启动参数
|
||||||
|
// };
|
||||||
|
const processOption = {
|
||||||
|
exe: '',
|
||||||
|
autoReOpen: true,
|
||||||
|
args: []
|
||||||
|
};
|
||||||
|
const service = new Process('./exe/NodeSharpTest.exe', (result, error) => {
|
||||||
|
// console.log('result:',result,error)
|
||||||
|
});
|
||||||
|
|
||||||
|
//exe已经运行时的 通信对象,要求是必须可以格式化为json字符串,而且必须有command字段
|
||||||
|
var onceParam = { command: 'once', data: "demo" };
|
||||||
|
// 一次性的回调,执行后即被回收
|
||||||
|
var onceFunction = function (err, data) { console.log(data); };
|
||||||
|
|
||||||
|
/***
|
||||||
|
var alwaysparam = { command: 'always', data: { demo: "this is demo date" } };
|
||||||
|
|
||||||
|
// 监听性的回调,创建后可伴随exe整个生命周期
|
||||||
|
var alwaysfun = function (err, data) {
|
||||||
|
if (err) {return console.error(err);}console.log(data);
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
// service.send(onceParam, onceFunction);
|
||||||
|
// exeservice.send(alwaysparam, function () { }, alwaysfun);
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const result = await service.send({ title: '测试标题', message: "内容xxx", number: '123123' }, 'print');
|
||||||
|
console.log('C# return result:', result)
|
||||||
|
} catch (e) {
|
||||||
|
console.log('C# return ', e)
|
||||||
|
}
|
||||||
|
service.exit();
|
||||||
|
})();
|
16
package.json
Normal file
16
package.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "csharp-process",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "call csharp process",
|
||||||
|
"main": "csharp-process.js",
|
||||||
|
"dependencies": {
|
||||||
|
"iconv-lite": "^0.4.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {},
|
||||||
|
"scripts": {
|
||||||
|
"dev": "node example.js"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user