first commit

This commit is contained in:
wumin 2021-02-10 22:41:24 +08:00
commit afbb62d536
5 changed files with 304 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
exe

43
README.MD Normal file
View 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
View 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
View 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
View 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"
}