UNPKG

storjshare-daemon

Version:

daemon + process manager for sharing space on the storj network

260 lines (230 loc) 6.32 kB
/** * @module utils */ 'use strict'; const dnode = require('dnode'); const net = require('net'); const fs = require('fs'); const storj = require('storj-lib'); const {bitcore} = storj.deps; const du = require('du'); // Get amount used const disk = require('diskusage'); // Get amount free const assert = require('assert'); const bytes = require('bytes'); const web3utils = require('web3-utils'); /** * Validate the given payout address * @param {String} address */ exports._isValidPayoutAddress = function(address) { return bitcore.Address.isValid(address) || bitcore.Address.isValid(address, bitcore.Networks.testnet) || this.isValidEthereumAddress(address); }; /** * Validate the given payout address is an Ethereum address * @param {String} address */ exports.isValidEthereumAddress = function(address) { //Disallow contract and contract owner addresses //Stops users from accidentally copying the wrong address const disallowAddresses = [ '0xb64ef51c888972c908cfacf59b47c1afbc0ab8ac', '0x00f6bf3c5033e944feddb3dc8ffb4d47af17ef0b' ]; if (typeof address !== 'string') { return false; } else if (disallowAddresses.indexOf(address.toLowerCase()) >= 0) { return false; } return /^0x/.test(address) && web3utils.isAddress(address); }; /** * Validate the given dataserv directory * @param {String} directory */ exports._isValidDirectory = function(directory) { return this.existsSync(directory); }; /** * Validate the given size * @param {String} size */ exports._isValidSize = function(size) { return typeof size === 'number' && size >= 0 && size <= 8 * Math.pow(2, 40); // 8TiB }; /** * Validates a given tab config * @param {Object} config */ exports.validate = function(config) { assert(this._isValidPayoutAddress(config.paymentAddress), 'Invalid payout address'); assert(this._isValidDirectory(config.storagePath), `Invalid directory: \ ${config.storagePath} does not exist`); assert(this._isValidSize(bytes.parse(config.storageAllocation)), 'Invalid storage size'); assert(this._isValidDirectory(config.storagePath), 'Could not create Shard Directory'); }; /** * Attempts to apply common fixes to a config * @param {Object} config */ exports.repairConfig = function(config) { // Check to see if the size is not using a storage unit if(!isNaN(parseInt(config.storageAllocation)) && this._isValidSize(config.storageAllocation)) { config.storageAllocation = config.storageAllocation.toString() + 'B'; } return config; }; /** * Validates the space being allocated exists * @param {Object} config */ exports.validateAllocation = function(conf, callback) { const self = this; if (!self._isValidStorageAllocationFormat(conf.storageAllocation)) { if (isNaN(conf.storageAllocation)) { return callback( new Error('Invalid storage size specified: '+ conf.storageAllocation) ); } conf.storageAllocation = conf.storageAllocation.toString() + 'B'; } callback(null); }; /** * Check if file exists * @param {String} file - Path to file */ exports.existsSync = function(file) { try { fs.statSync(file); } catch(err) { return !(err); } return true; }; /** * Check if StorageAllocation is formatted properly (Size + Unit) * @param {String} storage - storage Allocation from config */ exports._isValidStorageAllocationFormat = function(storageAllocation) { if (!storageAllocation.toString().match( /[0-9]+([Tt]|[Mm]|[Gg]|[Kk])?[Bb]/g) ) { return false; } return true; }; /** * Recursively determines the size of a directory * @param {String} dir - Directory to traverse * @param {Function} callback */ exports.getDirectorySize = function(dir, callback) { /* istanbul ignore next */ du(dir, { filter: function(f) { return f.indexOf('contracts.db') !== -1 || f.indexOf('sharddata.kfs') !== -1; } }, callback); }; /** * Get free space on disk of path * @param {String} path */ /* istanbul ignore next */ exports.getFreeSpace = function(path, callback) { if (!exports.existsSync(path)) { return callback(null, 0); } disk.check(path, function(err, info) { if (err) { return callback(err); } return callback(null, info.available); }); }; /** * Checks whether a port is currently in use or open * Callback is of form (err, result) * @param {Number} port * @param {Function} callback */ exports.portIsAvailable = function(port, callback) { if(typeof port !== 'number' || port < 0 || port > 65535) { return callback('Invalid port'); } else if (port <= 1024) { return callback( 'Using a port in the well-known range is strongly discouraged'); } let testServer = net.createServer() .once('error', function() { testServer.once('close', function() { callback(null, false); }) .close(); }) .once('listening', function() { testServer.once('close', function() { callback(null, true); }) .close(); }) .listen(port); }; /** * Checks the status of the daemon RPC server * @param {Number} port * @param {Function} callback * @param {String} hostname - optional */ exports.checkDaemonRpcStatus = function(port, callback, hostname = null) { if (!hostname) { hostname = '127.0.0.1'; } const sock = net.connect(port, hostname); sock.once('error', function() { callback(false); }); sock.once('connect', () => { sock.end(); callback(true); }); }; /** * Connects to the daemon and callback with rpc * @param {Number} port * @param {Function} callback * @param {String} hostname - optional */ exports.connectToDaemon = function(port, callback, hostname = null) { if (!hostname) { hostname = '127.0.0.1'; } const sock = dnode.connect(hostname, port); sock.on('error', function() { process.exitCode = 1; console.error('\n daemon is not running, try: storjshare daemon'); }); sock.on('remote', (rpc) => callback(rpc, sock)); }; /** * Get node Id by Private Key * @param {String} privateKey */ exports.getNodeID = function(privateKey) { let nodeId = null; try { nodeId = storj.KeyPair(privateKey).getNodeID(); } catch (err) { return null; } return nodeId; };