/ lib / modules / storage / storageProcessesLauncher.js
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;