Skip to content

Commit

Permalink
refine code
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangzifa authored and JacksonTian committed Mar 8, 2018
1 parent 5fb39fa commit 927d5ca
Show file tree
Hide file tree
Showing 11 changed files with 455 additions and 45 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Expand Up @@ -2,3 +2,4 @@
*.min.js
node_modules/*
app/public/*
coverage/*
4 changes: 3 additions & 1 deletion .gitignore
@@ -1,2 +1,4 @@
npm-debug.log
node_modules
node_modules
.nyc_output/
coverage/
11 changes: 11 additions & 0 deletions .travis.yml
@@ -0,0 +1,11 @@
sudo: false
language: node_js
node_js:
- '6'
- '8'
install:
- npm i npminstall && npminstall
script:
- npm run ci
after_script:
- npminstall codecov && codecov
286 changes: 252 additions & 34 deletions bin/agenthub
@@ -1,47 +1,265 @@
#!/usr/bin/env node
'use strict';

var path = require('path');
var nounou = require('nounou');
var util = require('util');
var clientPath = path.join(__dirname, '../client.js');
const os = require('os');
const fs = require('fs');
const path = require('path');
const child_process = require('child_process');
const spawn = child_process.spawn;

var argv = process.argv.slice(2);
const utils = require('../lib/utils');

var printUsage = function () {
console.log('参数错误。用法示例:');
console.log(' agenthub <config.json>');
console.log(' agenthub -v');
};
const SPLITTER = '\u0000';

const agenthubBin = path.join(__dirname, 'agenthub_main');
const agenthubStatusPath = path.join(os.homedir(), '.agenthub.pid');

const listHeader =
'|- App ID -|- PID -|---- Start Time -----|--- Config Path ------------------------------------|';

const listFooter =
'|----------|-------|---------------------|----------------------------------------------------|';

function pad(n) {
if (n < 10) {
return '0' + n;
}

return '' + n;
}

function timestamp(time) {
var date = new Date();
date.setTime(+time);
const YYYY = date.getFullYear();
const MM = pad(date.getMonth() + 1);
const DD = pad(date.getDate());
const HH = pad(date.getHours());
const mm = pad(date.getMinutes());
const ss = pad(date.getSeconds());
return `${YYYY}-${MM}-${DD} ${HH}:${mm}:${ss}`;
}

function format(data, width) {
data = data.toString();
if (data.length >= width) {
return data;
}
// 靠右对齐
return ' '.repeat(width - data.length) + data;
}

function contentShaping(appid, pid, config, startTime) {
appid = format(appid, 8);
pid = format(pid, 5);
config = format(config, 40);
startTime = timestamp(startTime);
return '| ' + [appid, pid, startTime, config].join(' | ') + ' |';
}

function appendAgenthubStatus(appid, pid, config) {
const line = [appid, pid, config, Date.now()].join(SPLITTER) + '\n';
fs.appendFileSync(agenthubStatusPath, line);
}

function killRunning(pid) {
try {
process.kill(pid);
} catch (ex) {
return false;
}
}

function isAppid(appid) {
if (!appid) {
return false;
}

appid = appid.toString();
if (appid.length === 0) {
return false;
}

return /\d*/.test(appid);
}

function isAlive(pid) {
try {
return process.kill(pid, 0);
} catch (ex) {
return false;
}
}

function start(configPath) {
if (!configPath) {
console.log('config.json not provided.');
console.log();
console.log('Usage: ');
console.log(' agenthub start /path/to/config.json');
process.exit(1);
}

configPath = path.resolve(configPath);
if (!fs.existsSync(configPath)) {
console.log('%s not exists.', configPath);
process.exit(1);
}

if (!configPath.endsWith('.json')) {
console.log('%s must be a JSON file.', configPath);
process.exit(1);
}

var cfg;
try {
cfg = require(configPath);
} catch (ex) {
console.log('%s must be a valid JSON file.', configPath);
console.log('Error stack:');
console.log(ex.stack);
process.exit(1);
}

if (!cfg.appid || ! cfg.secret) {
console.log('`appid` and `secret` must be provided.');
process.exit(1);
}

var appid = cfg.appid;
var proc = spawn(agenthubBin, [configPath], {detached: true});
console.log('agenthub has started(pid: %s).', proc.pid);
appendAgenthubStatus(appid, proc.pid, configPath);
process.exit(0);
}

function getAlives() {
var raw = fs.readFileSync(agenthubStatusPath, 'utf8').trim().split('\n');
var agenthubs = raw.filter(function(line) {
return line.length > 0;
}).map(function(line) {
const [appid, pid, config, startTime] = line.split(SPLITTER);
return {appid, pid, config, startTime};
});

var alives = agenthubs.filter(function(item) {
return isAlive(item.pid);
});

return alives;
}

function writeBackAlives(alives) {
fs.writeFileSync(agenthubStatusPath, alives.map((item) => {
return [item.appid, item.pid, item.config, item.startTime]
.join(SPLITTER) + '\n';
}).join(''));
}

function list() {
/*
* get from ~/.agenthub.pid
* return [{appid: 123, pid: 3868, config: '/path/to/config.json'}, ... ]
*/
if (!fs.existsSync(agenthubStatusPath)) {
console.log('There is no running agenthub.');
process.exit(0);
}

const alives = getAlives();

writeBackAlives(alives);

if (alives.length === 0) {
console.log('There is no running agenthub.');
process.exit(0);
}

console.log(listHeader);
alives.forEach(function(item) {
console.log(contentShaping(item.appid, item.pid, item.config, item.startTime));
});
console.log(listFooter);
process.exit(0);
}

function stopAll() {
const alives = getAlives();
alives.forEach(function(item) {
killRunning(item.pid);
});

writeBackAlives([]);
}

function stopApp(appid) {
const alives = getAlives();
if (!alives.find(function (item) {
return item.appid === appid;
})) {
console.log(`There is no running agenthub for appid: ${appid}.`);
return;
}

const newlist = alives.filter(function(item) {
if (item.appid === appid) {
killRunning(item.pid);
return false;
}
return true;
});

writeBackAlives(newlist);
}

function stop(input) {
if (input === 'all') {
stopAll();
process.exit(0);
} else if (isAppid(input)) {
stopApp(input);
process.exit(0);
} else {
console.log('agenthub stop all stop all agenthubs');
console.log('agenthub stop <appid> stop the agenthub(s) for appid');
process.exit(1);
}
}

const argv = process.argv.slice(2);

if (argv.length < 1) {
printUsage();
console.log(utils.helpText);
process.exit(1);
}

if (argv[0] === '-v') {
switch (argv[0]) {
case '-v':
case '--version':
case 'version':
console.log(require('../package.json').version);
process.exit(0);
break;
case '-h':
case '--help':
case 'help':
console.log(utils.helpText);
process.exit(0);
break;
case 'start':
start(argv[1]);
break;
case 'list':
list();
break;
case 'stop':
stop(argv[1]);
break;
default:
// 兼容旧的形式
if (argv[0].endsWith('.json')) {
start(argv[0]);
}
console.log(utils.helpText);
process.exit(1);
}

nounou(clientPath, {
args: [argv[0]],
count: 1
})
.on('fork', function (client) {
console.log('[%s] [client:%d] new client start', Date(), client.pid);
})
.on('disconnect', function (client) {
console.error('[%s] [%s] client:%s disconnect, suicide: %s.',
Date(), process.pid, client.pid, client.suicide);
})
.on('expectedExit', function (client, code, signal) {
console.log('[%s] [%s], client %s died (code: %s, signal: %s)', Date(),
process.pid, client.pid, code, signal);
})
.on('unexpectedExit', function (client, code, signal) {
var err = new Error(util.format('client %s died (code: %s, signal: %s)',
client.pid, code, signal));
err.name = 'ClientDiedError';
console.error('[%s] [%s] client exit: %s', Date(), process.pid, err.stack);
});
27 changes: 27 additions & 0 deletions bin/agenthub_main
@@ -0,0 +1,27 @@
#!/usr/bin/env node

'use strict';

const path = require('path');
const nounou = require('nounou');
const clientPath = path.join(__dirname, '../lib/client.js');
const argv = process.argv.slice(2);

const cfgPath = argv[0];

nounou(clientPath, {
args: [cfgPath],
count: 1
}).on('fork', function (client) {
console.log('[%s] [client:%d] new client start', Date(), client.pid);
}).on('disconnect', function (client) {
console.error('[%s] [%s] client:%s disconnect, suicide: %s.',
Date(), process.pid, client.pid, client.suicide);
}).on('expectedExit', function (client, code, signal) {
console.log('[%s] [%s], client %s died (code: %s, signal: %s)', Date(),
process.pid, client.pid, code, signal);
}).on('unexpectedExit', function (client, code, signal) {
var err = new Error(`client ${client.pid} died (code: ${code}, signal: ${signal})`);
err.name = 'ClientDiedError';
console.error('[%s] [%s] client exit: %s', Date(), process.pid, err.stack);
});
5 changes: 3 additions & 2 deletions agenthub.js → lib/agenthub.js
@@ -1,9 +1,10 @@
'use strict';

const path = require('path');
const commandxPath = path.dirname(require.resolve('commandx/package.json'));
const Agentx = require('agentx');
const AgentX = require('agentx');

class AgentHub extends Agentx {
class AgentHub extends AgentX {
constructor(config) {
super(Object.assign({
server: 'wss://agentserver.node.aliyun.com:8080',
Expand Down
10 changes: 5 additions & 5 deletions client.js → lib/client.js
@@ -1,7 +1,7 @@
'use strict';

var path = require('path');
var argv = process.argv.slice(2);
const path = require('path');
const argv = process.argv.slice(2);

// exiting with parent process
process.on('disconnect', function () {
Expand Down Expand Up @@ -31,7 +31,7 @@ process.on('uncaughtException', function (err) {
process.exit(-1);
});

var AgentHub = require('./agenthub');
var confPath = path.resolve(argv[0]);
var agenthub = new AgentHub(readConfig(confPath));
const AgentHub = require('./agenthub');
const confPath = path.resolve(argv[0]);
const agenthub = new AgentHub(readConfig(confPath));
agenthub.run();

0 comments on commit 927d5ca

Please sign in to comment.