blinksocks/bin/bootstrap.js
2017-04-07 16:03:53 +08:00

152 lines
4.8 KiB
JavaScript

const fs = require('fs');
const program = require('commander');
const packageJson = require('../package.json');
// const BOOTSTRAP_TYPE_CLIENT = 0;
const BOOTSTRAP_TYPE_SERVER = 1;
const version = packageJson.version;
const usage = '--host <host> --port <port> --key <key> [...]';
const options = [
['-c, --config [file]', 'a json format file for configuration', ''],
['--host <host>', 'an ip address or a hostname to bind, default: \'localhost\'', 'localhost'],
['--port <port>', 'where to listen on, default: 1080', 1080],
['--servers [servers]', 'a list of servers used by client, split by comma, default: \'\'', (value) => value.split(','), []],
['--key <key>', 'a key for encryption and decryption'],
['--frame [frame]', 'a preset used in frame middleware, default: \'origin\'', 'origin'],
['--frame-params [crypto-params]', 'parameters for frame preset, default: \'\'', ''],
['--crypto [crypto]', 'a preset used in crypto middleware, default: \'\'', ''],
['--crypto-params [crypto-params]', 'parameters for crypto, default: \'aes-256-cfb\'', 'aes-256-cfb'],
['--protocol [protocol]', 'a preset used in protocol middleware, default: \'aead\'', 'aead'],
['--protocol-params [protocol-params]', 'parameters for protocol, default: \'aes-256-gcm,ss-subkey\'', 'aes-256-gcm,ss-subkey'],
['--obfs [obfs]', 'a preset used in obfs middleware, default: \'\'', ''],
['--obfs-params [obfs-params]', 'parameters for obfs, default: \'\'', ''],
['--redirect [redirect]', 'redirect stream to here when any preset fail to process, default: \'\'', ''],
['--log-level [log-level]', 'log level, default: \'silly\'', 'silly'],
['-q, --quiet [quiet]', 'force log level to \'error\', default: false', false],
['-w, --watch [watch]', 'hot reload config.json specified via -c, default: true', true],
['--profile [profile]', 'generate performance statistics, store at blinksocks.profile.log once exit, default: false', false]
];
const examples = `
Examples:
As simple as possible:
$ blinksocks client -c config.json --watch
To start a server:
$ blinksocks server --host 0.0.0.0 --port 7777 --key password
To start a client:
$ blinksocks client --host localhost --port 1080 --key password --servers=node1.test.com:7777,node2.test.com:7777
`;
/**
* get raw config object from json or command line options
* @param type, BOOTSTRAP_TYPE_CLIENT or BOOTSTRAP_TYPE_SERVER
* @param options
* @returns {object}
*/
function obtainConfig(type, options) {
// CLI options should be able to overwrite options specified in --config
const {host, servers, key, quiet} = options;
const {frame, crypto, protocol, obfs, redirect} = options;
// renames
const [frame_params, crypto_params, protocol_params, obfs_params] = [
options.frameParams,
options.cryptoParams,
options.protocolParams,
options.obfsParams
];
// pre-process
const [port, log_level, watch, profile] = [
parseInt(options.port, 10),
quiet ? 'error' : options.logLevel,
!!options.watch,
!!options.profile
];
// assemble, undefined fields will be omitted
const config = {
host,
port,
servers,
key,
frame,
frame_params,
crypto,
crypto_params,
protocol,
protocol_params,
obfs,
obfs_params,
redirect,
log_level,
watch,
profile
};
// --config, if provided, options in config.json should be able to overwrite CLI options
if (options.config !== '') {
const file = options.config;
try {
const jsonFile = fs.readFileSync(file);
Object.assign(config, JSON.parse(jsonFile));
} catch (err) {
throw Error(`error parse your \'${file}\'`);
}
}
/// post-process
if (type === BOOTSTRAP_TYPE_SERVER) {
delete config.servers;
} else {
config.servers = config.servers.filter((server) => server[0] !== '-');
}
return config;
}
module.exports = function (type, {Hub, Config}) {
const pg = program.version(version).usage(usage);
for (const option of options) {
pg.option(...option);
}
program.on('--help', () => console.log(examples));
program.parse(process.argv);
// no options provided
if (process.argv.length < 3) {
program.help();
process.exit(0);
}
if (program.config !== '' && program.watch) {
fs.watchFile(program.config, function (curr, prev) {
if (curr.mtime > prev.mtime) {
console.log(`==> [bootstrap] ${program.config} has changed, reload`);
try {
Config.init(obtainConfig(type, program));
console.info(JSON.stringify(Config.abstract(), null, ' '));
} catch (err) {
console.error(err.message);
}
}
});
}
try {
Config.init(obtainConfig(type, program));
const app = new Hub();
app.run();
process.on('SIGINT', () => app.onClose());
} catch (err) {
console.error(err.message);
process.exit(-1);
}
};