storageProcessesLauncher.js
1 const fs = require('../../core/fs'); 2 const shellJs = require('shelljs'); 3 const utils = require('../../utils/utils'); 4 const ProcessLauncher = require('../../core/processes/processLauncher'); 5 const constants = require('../../constants'); 6 const {canonicalHost} = require('../../utils/host'); 7 const cloneDeep = require('lodash.clonedeep'); 8 9 let References = { 10 ipfs: 'https://ipfs.io/docs/install/', 11 swarm: 'http://swarm-guide.readthedocs.io/en/latest/installation.html' 12 }; 13 14 class StorageProcessesLauncher { 15 constructor(options) { 16 this.logger = options.logger; 17 this.events = options.events; 18 this.storageConfig = options.storageConfig; 19 this.webServerConfig = options.webServerConfig; 20 this.blockchainConfig = options.blockchainConfig; 21 this.embark = options.embark; 22 this.processes = {}; 23 this.corsParts = options.corsParts || []; 24 25 this.cors = this.buildCors(); 26 27 this.events.on('exit', () => { 28 Object.keys(this.processes).forEach(processName => { 29 this.processes[processName].send('exit'); 30 }); 31 }); 32 } 33 34 buildCors() 35 { 36 let corsParts = cloneDeep(this.corsParts); 37 // add our webserver CORS 38 if(this.webServerConfig.enabled){ 39 if (this.webServerConfig && this.webServerConfig.host) { 40 corsParts.push(utils.buildUrlFromConfig(this.webServerConfig)); 41 } 42 else corsParts.push('http://localhost:8000'); 43 } 44 45 // add all dapp connection storage 46 if(this.storageConfig.enabled) { 47 this.storageConfig.dappConnection.forEach(dappConn => { 48 if(dappConn.getUrl || dappConn.host){ 49 50 // if getUrl is specified in the config, that needs to be included in cors 51 // instead of the concatenated protocol://host:port 52 if(dappConn.getUrl) { 53 // remove /ipfs or /bzz: from getUrl if it's there 54 let getUrlParts = dappConn.getUrl.split('/'); 55 getUrlParts = getUrlParts.slice(0, 3); 56 let host = canonicalHost(getUrlParts[2].split(':')[0]); 57 let port = getUrlParts[2].split(':')[1]; 58 getUrlParts[2] = port ? [host, port].join(':') : host; 59 corsParts.push(getUrlParts.join('/')); 60 } 61 // in case getUrl wasn't specified, use a built url 62 else{ 63 corsParts.push(utils.buildUrlFromConfig(dappConn)); 64 } 65 } 66 }); 67 } 68 69 if(this.blockchainConfig.enabled) { 70 // add our rpc endpoints to CORS 71 if(this.blockchainConfig.rpcHost && this.blockchainConfig.rpcPort){ 72 corsParts.push(`http://${canonicalHost(this.blockchainConfig.rpcHost)}:${this.blockchainConfig.rpcPort}`); 73 } 74 75 // add our ws endpoints to CORS 76 if(this.blockchainConfig.wsRPC && this.blockchainConfig.wsHost && this.blockchainConfig.wsPort){ 77 corsParts.push(`ws://${canonicalHost(this.blockchainConfig.wsHost)}:${this.blockchainConfig.wsPort}`); 78 } 79 } 80 return corsParts; 81 } 82 83 processExited(storageName, code) { 84 this.logger.error(__(`Storage process for {{storageName}} ended before the end of this process. Code: {{code}}`, {storageName, code})); 85 } 86 87 launchProcess(storageName, callback) { 88 const self = this; 89 callback = callback || function () {}; 90 91 if (self.processes[storageName]) { 92 return callback(__('Storage process already started')); 93 } 94 const filePath = utils.joinPath(__dirname, `../${storageName}/process.js`); 95 fs.access(filePath, (err) => { 96 if (err) { 97 return callback(__('No process file for this storage type (%s) exists. Please start the process locally.', storageName)); 98 } 99 100 let cmd = (storageName === 'swarm' ? (self.storageConfig.swarmPath || 'swarm') : 'ipfs'); 101 102 const program = shellJs.which(cmd); 103 if (!program) { 104 self.logger.warn(__('{{storageName}} is not installed or your configuration is not right', {storageName}).yellow); 105 self.logger.info(__('You can install and get more information here: ').yellow + References[storageName].underline); 106 return callback(__('%s not installed', storageName)); 107 } 108 109 self.logger.info(__(`Starting %s process`, storageName).cyan); 110 self.processes[storageName] = new ProcessLauncher({ 111 modulePath: filePath, 112 name: storageName, 113 logger: self.logger, 114 events: self.events, 115 embark: self.embark, 116 silent: self.logger.logLevel !== 'trace', 117 exitCallback: self.processExited.bind(this, storageName) 118 }); 119 this.events.once("blockchain:ready", () => { 120 this.events.request("blockchain:object", (blockchain) => { 121 blockchain.determineDefaultAccount((err, defaultAccount) => { 122 if (err) { 123 return callback(err); 124 } 125 self.processes[storageName].send({ 126 action: constants.storage.init, options: { 127 storageConfig: self.storageConfig, 128 blockchainConfig: self.blockchainConfig, 129 cors: self.buildCors(), 130 defaultAccount: defaultAccount 131 } 132 }); 133 }); 134 }); 135 }); 136 137 138 self.processes[storageName].on('result', constants.storage.initiated, (msg) => { 139 if (msg.error) { 140 self.processes[storageName].disconnect(); 141 delete self.processes[storageName]; 142 return callback(msg.error); 143 } 144 self.logger.info(__(`${storageName} process started`).cyan); 145 callback(); 146 }); 147 148 self.events.on('logs:swarm:enable', () => { 149 self.processes[storageName].silent = false; 150 }); 151 152 self.events.on('logs:swarm:disable', () => { 153 self.processes[storageName].silent = true; 154 }); 155 156 }); 157 } 158 } 159 160 module.exports = StorageProcessesLauncher;