core: fix 100% cpu when sub process fail to start
This commit is contained in:
parent
dd5397aa1e
commit
b0939ac4ed
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -1,5 +1,17 @@
|
|||
# 更新日志
|
||||
|
||||
## 0.3.1 (2018-11-24)
|
||||
|
||||
### :bug: Bug 修复:
|
||||
|
||||
- 修复子进程(blinksocks)启动失败导致 CPU 占满的问题
|
||||
|
||||
### 从 0.3.0 更新到 0.3.1
|
||||
|
||||
```
|
||||
$ npm install -g blinksocks-gui@0.3.1 blinksocks@3.x
|
||||
```
|
||||
|
||||
## 0.3.0 (2018-05-14)
|
||||
|
||||
### :rocket: 新功能和改进
|
||||
|
|
18
README.md
18
README.md
|
@ -5,18 +5,12 @@
|
|||
[![license](https://img.shields.io/npm/l/blinksocks-gui.svg)](https://github.com/blinksocks/blinksocks-gui/blob/master/LICENSE)
|
||||
[![%e2%9d%a4](https://img.shields.io/badge/made%20with-%e2%9d%a4-ff69b4.svg)](https://github.com/blinksocks/blinksocks-gui)
|
||||
|
||||
为 [blinksocks](https://github.com/blinksocks/blinksocks) 封装的 WEB 图形化界面。
|
||||
> 为 [blinksocks](https://github.com/blinksocks/blinksocks) 封装的 WEB 图形化界面。
|
||||
|
||||
![](screenshot-0.png)
|
||||
|
||||
![](screenshot-1.png)
|
||||
|
||||
![](screenshot-2.png)
|
||||
|
||||
## 在线体验(只读模式)
|
||||
|
||||
https://gui.blinksocks.org/landing?password=preview
|
||||
|
||||
## 特性
|
||||
|
||||
- 三大平台支持(Windows、Linux、macOS)
|
||||
|
@ -43,18 +37,10 @@ $ npm install -g blinksocks blinksocks-gui
|
|||
|
||||
需要升级时重新执行上面的命令即可。
|
||||
|
||||
### 使用预编译版本
|
||||
|
||||
> 使用预编译版本无需安装 Node.js 和其他依赖软件,但升级时必须重新下载、解压和替换整个软件包。
|
||||
|
||||
下载地址:https://github.com/blinksocks/blinksocks-gui/releases
|
||||
|
||||
## 启动
|
||||
|
||||
### 交互式启动
|
||||
|
||||
桌面环境双击直接运行,服务器环境从命令行启动:
|
||||
|
||||
```
|
||||
$ NODE_ENV=production blinksocks-gui
|
||||
```
|
||||
|
@ -86,7 +72,7 @@ info: You can now open blinksocks-gui in browser:
|
|||
|
||||
```
|
||||
|
||||
### 命令行启动
|
||||
### 一行命令启动
|
||||
|
||||
```
|
||||
$ blinksocks-gui --client --port 3000
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "blinksocks-gui",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"description": "A web based GUI wrapper for blinksocks",
|
||||
"author": "Micooz",
|
||||
"files": [
|
||||
|
@ -33,6 +33,7 @@
|
|||
"lodash": "^4.17.10",
|
||||
"lodash-id": "^0.14.0",
|
||||
"lowdb": "^1.0.0",
|
||||
"node-ipc-call": "0.0.3",
|
||||
"pidusage": "^2.0.6",
|
||||
"prompts": "^0.1.8",
|
||||
"socket.io": "^2.1.1",
|
||||
|
@ -42,7 +43,7 @@
|
|||
"devDependencies": {
|
||||
"cross-env": "^5.1.6",
|
||||
"nodemon": "^1.17.5",
|
||||
"pkg": "^4.3.1",
|
||||
"pkg": "^4.3.4",
|
||||
"rimraf": "^2.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const pidusage = require('pidusage');
|
||||
const dateFns = require('date-fns');
|
||||
const { Callee } = require('node-ipc-call');
|
||||
|
||||
const { Hub } = require('blinksocks');
|
||||
|
||||
|
@ -126,9 +127,10 @@ const Monitor = {
|
|||
|
||||
};
|
||||
|
||||
// process methods mapping
|
||||
const methods = {
|
||||
const callee = new Callee();
|
||||
|
||||
// process methods mapping
|
||||
callee.register({
|
||||
// start hub
|
||||
'start': async function start(config) {
|
||||
if (!hub) {
|
||||
|
@ -170,22 +172,6 @@ const methods = {
|
|||
'getConnectionsMetrics': () => Monitor.getConnectionsMetrics(),
|
||||
// get current process upload traffic and download traffic
|
||||
'getTrafficMetrics': () => [Monitor.getUploadTrafficMetrics(), Monitor.getDownloadTrafficMetrics()],
|
||||
|
||||
};
|
||||
|
||||
process.on('message', async (action) => {
|
||||
if (typeof action !== 'object') {
|
||||
return;
|
||||
}
|
||||
const { type, payload } = action;
|
||||
const func = methods[type];
|
||||
if (typeof func !== 'function') {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const result = await func(payload);
|
||||
process.send({ type: type + '/done', payload: result });
|
||||
} catch (err) {
|
||||
process.send({ type: type + '/error', payload: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
callee.listen();
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
const path = require('path');
|
||||
const child_process = require('child_process');
|
||||
const _ = require('lodash');
|
||||
const { Caller } = require('node-ipc-call');
|
||||
|
||||
const db = require('./db');
|
||||
const logger = require('./logger');
|
||||
const GeoIP = require('./geoip');
|
||||
|
||||
const {
|
||||
|
@ -15,92 +14,6 @@ const {
|
|||
|
||||
const FORK_SCRIPT = path.resolve(__dirname, '_fork.js');
|
||||
|
||||
// create a new sub process
|
||||
function create() {
|
||||
const subprocess = child_process.fork(FORK_SCRIPT, {
|
||||
cwd: RUNTIME_PATH,
|
||||
silent: process.env.NODE_ENV === 'production',
|
||||
});
|
||||
const geoip = new GeoIP();
|
||||
geoip.put(db.get('runtime.ip').value(), { self: true });
|
||||
|
||||
const messageQueue = [];
|
||||
|
||||
subprocess.on('message', (message) => {
|
||||
if (typeof message !== 'object') {
|
||||
// drop non-object message
|
||||
return;
|
||||
}
|
||||
messageQueue.push(message);
|
||||
});
|
||||
subprocess.on('error', (err) => {
|
||||
logger.error(err.stack);
|
||||
});
|
||||
|
||||
async function send(action) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!subprocess.connected) {
|
||||
return reject(Error('child process is not available'));
|
||||
}
|
||||
// send message to sub process immediately
|
||||
subprocess.send(action);
|
||||
|
||||
function scanQueue() {
|
||||
for (let i = 0; i < messageQueue.length; i++) {
|
||||
const message = messageQueue[i];
|
||||
// find related message from sub process
|
||||
if (message.type.indexOf(action.type) === 0) {
|
||||
const { type, payload } = message;
|
||||
if (type === action.type + '/error') {
|
||||
reject(Error(payload));
|
||||
return i;
|
||||
}
|
||||
if (type === action.type + '/done') {
|
||||
resolve(payload);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// consume messageQueue
|
||||
setImmediate(function consume() {
|
||||
const index = scanQueue();
|
||||
// if not found, continue to consume,
|
||||
if (index < 0) {
|
||||
setImmediate(consume);
|
||||
}
|
||||
// if message found, remove it from queue.
|
||||
else {
|
||||
messageQueue.splice(index, 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
// GeoIP instance
|
||||
geoip: geoip,
|
||||
|
||||
// return original <ChildProcess>
|
||||
get process() {
|
||||
return subprocess;
|
||||
},
|
||||
|
||||
// call any methods of forked process
|
||||
async invoke(method, args) {
|
||||
return send({ type: method, payload: args });
|
||||
},
|
||||
|
||||
// destroy this object
|
||||
destroy() {
|
||||
subprocess.kill();
|
||||
geoip.clear();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
_subprocesses: new Map(/* <id>: <ChildProcess> */),
|
||||
|
@ -108,7 +21,12 @@ module.exports = {
|
|||
async start(id, config) {
|
||||
let sub = this._subprocesses.get(id);
|
||||
if (!sub) {
|
||||
sub = create();
|
||||
sub = Caller.fork(FORK_SCRIPT, [], {
|
||||
cwd: RUNTIME_PATH,
|
||||
silent: process.env.NODE_ENV === 'production',
|
||||
});
|
||||
sub.geoip = new GeoIP();
|
||||
sub.geoip.put(db.get('runtime.ip').value(), { self: true });
|
||||
this._subprocesses.set(id, sub);
|
||||
}
|
||||
try {
|
||||
|
@ -127,6 +45,7 @@ module.exports = {
|
|||
if (sub) {
|
||||
await sub.invoke('stop');
|
||||
sub.destroy();
|
||||
sub.geoip.clear();
|
||||
this._subprocesses.set(id, null);
|
||||
} else {
|
||||
throw Error(`service(${id}) is not found`);
|
||||
|
|
BIN
screenshot-1.png
BIN
screenshot-1.png
Binary file not shown.
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 81 KiB |
BIN
screenshot-2.png
BIN
screenshot-2.png
Binary file not shown.
Before Width: | Height: | Size: 81 KiB |
Loading…
Reference in New Issue