storjshare-daemon
Version:
daemon + process manager for sharing space on the storj network
202 lines (171 loc) • 6.51 kB
JavaScript
;
const blindfold = require('blindfold');
const editor = require('editor');
const {homedir} = require('os');
const fs = require('fs');
const storj = require('storj-lib');
const path = require('path');
const mkdirp = require('mkdirp');
const stripJsonComments = require('strip-json-comments');
const storjshare_create = require('commander');
const {execSync} = require('child_process');
const utils = require('../lib/utils');
const touch = require('touch');
const defaultConfig = JSON.parse(stripJsonComments(fs.readFileSync(
path.join(__dirname, '../example/farmer.config.json')
).toString()));
function whichEditor() {
const editors = ['vi', 'nano'];
function checkIsInstalled(editor) {
try {
execSync('which ' + editor);
} catch (err) {
return false;
}
return true;
}
for (let i = 0; i < editors.length; i++) {
if (checkIsInstalled(editors[i])) {
return editors[i];
}
}
return null;
}
storjshare_create
.description('generates a new node configuration')
.option('--storj <addr>', 'specify the STORJ address (required)')
.option('--key <privkey>', 'specify the private key')
.option('--storage <path>', 'specify the storage path')
.option('--size <maxsize>', 'specify node size (ex: 10GB, 1TB)')
.option('--rpcport <port>', 'specify the rpc port number')
.option('--rpcaddress <addr>', 'specify the rpc address')
.option('--maxtunnels <tunnels>', 'specify the max tunnels')
.option('--tunnelportmin <port>', 'specify min gateway port')
.option('--tunnelportmax <port>', 'specify max gateway port')
.option('--manualforwarding', 'do not use nat traversal strategies')
.option('--verbosity <verbosity>', 'specify the logger verbosity')
.option('--logdir <path>', 'specify the log directory')
.option('--noedit', 'do not open generated config in editor')
.option('-o, --outfile <writepath>', 'write config to path')
.parse(process.argv);
if (!storjshare_create.storj) {
console.error('\n no payment address was given, try --help');
process.exit(1);
}
if (!utils.isValidEthereumAddress(storjshare_create.storj)) {
console.error('\n SJCX addresses are no longer supported. \
Please enter ERC20 compatible ETH wallet address');
process.exit(1);
}
if (!storjshare_create.key) {
storjshare_create.key = storj.KeyPair().getPrivateKey();
}
if (!storjshare_create.storage) {
storjshare_create.storage = path.join(
homedir(),
'.config/storjshare/shares',
storj.KeyPair(storjshare_create.key).getNodeID()
);
mkdirp.sync(storjshare_create.storage);
}
if (!storjshare_create.outfile) {
const configDir = path.join(homedir(), '.config/storjshare/configs');
storjshare_create.outfile = path.join(
configDir, storj.KeyPair(storjshare_create.key).getNodeID() + '.json'
);
mkdirp.sync(configDir);
touch.sync(storjshare_create.outfile);
}
if (!storjshare_create.logdir) {
storjshare_create.logdir = path.join(
homedir(),
'.config/storjshare/logs'
);
mkdirp.sync(storjshare_create.logdir);
}
if (storjshare_create.size &&
!storjshare_create.size.match(/[0-9]+(T|M|G|K)?B/g)) {
console.error('\n Invalid storage size specified: '+
storjshare_create.size);
process.exit(1);
}
let exampleConfigPath = path.join(__dirname, '../example/farmer.config.json');
let exampleConfigString = fs.readFileSync(exampleConfigPath).toString();
function getDefaultConfigValue(prop) {
return {
value: blindfold(defaultConfig, prop),
type: typeof blindfold(defaultConfig, prop)
};
}
function replaceDefaultConfigValue(prop, value) {
let defaultValue = getDefaultConfigValue(prop);
function toStringReplace(prop, value, type) {
switch (type) {
case 'string':
value = value.split('\\').join('\\\\'); // NB: Hack windows paths
return`"${prop}": "${value}"`;
case 'boolean':
case 'number':
return `"${prop}": ${value}`;
default:
return '';
}
}
let validVerbosities = new RegExp(/^[0-4]$/);
if (storjshare_create.verbosity &&
!validVerbosities.test(storjshare_create.verbosity)) {
console.error('\n * Invalid verbosity.\n * Accepted values: 4 - DEBUG | \
3 - INFO | 2 - WARN | 1 - ERROR | 0 - SILENT\n * Default value of %s \
will be used.', getDefaultConfigValue('loggerVerbosity').value);
storjshare_create.verbosity = null;
}
prop = prop.split('.').pop();
exampleConfigString = exampleConfigString.replace(
toStringReplace(prop, defaultValue.value, defaultValue.type),
toStringReplace(prop, value, defaultValue.type)
);
}
replaceDefaultConfigValue('paymentAddress', storjshare_create.storj);
replaceDefaultConfigValue('networkPrivateKey', storjshare_create.key);
replaceDefaultConfigValue('storagePath',
path.normalize(storjshare_create.storage));
replaceDefaultConfigValue('loggerOutputFile',
path.normalize(storjshare_create.logdir));
const optionalReplacements = [
{ option: storjshare_create.size, name: 'storageAllocation' },
{ option: storjshare_create.rpcaddress, name: 'rpcAddress' },
{ option: storjshare_create.rpcport, name: 'rpcPort' },
{ option: storjshare_create.maxtunnels, name: 'maxTunnels' },
{ option: storjshare_create.tunnelportmin, name: 'tunnelGatewayRange.min' },
{ option: storjshare_create.tunnelportmax, name: 'tunnelGatewayRange.max' },
{ option: storjshare_create.manualforwarding, name: 'doNotTraverseNat' },
{ option: storjshare_create.verbosity, name: 'loggerVerbosity' }
];
optionalReplacements.forEach((repl) => {
if (repl.option) {
replaceDefaultConfigValue(repl.name, repl.option);
}
});
let outfile = path.isAbsolute(storjshare_create.outfile) ?
path.normalize(storjshare_create.outfile) :
path.join(process.cwd(), storjshare_create.outfile);
try {
fs.writeFileSync(outfile, exampleConfigString);
} catch (err) {
console.log (`\n failed to write config, reason: ${err.message}`);
process.exit(1);
}
console.log(`\n * configuration written to ${outfile}`);
if (!storjshare_create.noedit) {
console.log(' * opening in your favorite editor to tweak before running');
editor(outfile, {
// NB: Not all distros ship with vim, so let's use GNU Nano
editor: process.platform === 'win32'
? null
: whichEditor()
}, () => {
console.log(' ...');
console.log(` * use new config: storjshare start --config ${outfile}`);
});
}