<commit_before>const electron = require('electron'),
      app = electron.app,
      BrowserWindow = electron.BrowserWindow,
      path = require('path'),
      url = require('url'),
      os = require('os'),
      fsnode = require('fs'),
      fs = require('fs-extra'),
      _fs = require('graceful-fs'),
      mkdirp = require('mkdirp'),
      express = require('express'),
      exec = require('child_process').exec,
      spawn = require('child_process').spawn,
      md5 = require('md5'),
      pm2 = require('pm2'),
      request = require('request'),
      async = require('async'),
      rimraf = require('rimraf'),
      portscanner = require('portscanner'),
      Promise = require('bluebird');

const fixPath = require('fix-path');
var ps = require('ps-node'),
    setconf = require('../private/setconf.js'),
    //coincli = require('../private/coincli.js'),
    assetChainPorts = require('./ports.js')
    shepherd = express.Router(),
    iguanaInstanceRegistry = {},
    syncOnlyIguanaInstanceInfo = {},
    syncOnlyInstanceInterval = -1;

// IGUANA FILES AND CONFIG SETTINGS
var iguanaConfsDirSrc = path.join(__dirname, '../assets/deps/confs'),
    CorsProxyBin = path.join(__dirname, '../node_modules/corsproxy/bin/corsproxy');

// SETTING OS DIR TO RUN IGUANA FROM
// SETTING APP ICON FOR LINUX AND WINDOWS
if (os.platform() === 'darwin') {
  fixPath();
  var iguanaBin = path.join(__dirname, '../assets/bin/osx/iguana'),
      iguanaDir = process.env.HOME + '/Library/Application Support/iguana',
      iguanaConfsDir = iguanaDir + '/confs',
      komododBin = path.join(__dirname, '../assets/bin/osx/komodod'),
      komodocliBin = path.join(__dirname, '../assets/bin/osx/komodo-cli'),
      komodoDir = process.env.HOME + '/Library/Application Support/Komodo';

      zcashdBin = '/Applications/ZCashSwingWalletUI.app/Contents/MacOS/zcashd',
      zcashcliBin = '/Applications/ZCashSwingWalletUI.app/Contents/MacOS/zcash-cli',
      zcashDir = process.env.HOME + '/Library/Application Support/Zcash';
}

if (os.platform() === 'linux') {
  var iguanaBin = path.join(__dirname, '../assets/bin/linux64/iguana'),
      iguanaDir = process.env.HOME + '/.iguana',
      iguanaConfsDir = iguanaDir + '/confs',
      iguanaIcon = path.join(__dirname, '/assets/icons/agama_icons/128x128.png'),
      komododBin = path.join(__dirname, '../assets/bin/linux64/komodod'),
      komodocliBin = path.join(__dirname, '../assets/bin/linux64/komodo-cli'),
      komodoDir = process.env.HOME + '/.komodo';
}

if (os.platform() === 'win32') {
  var iguanaBin = path.join(__dirname, '../assets/bin/win64/iguana.exe');
      iguanaBin = path.normalize(iguanaBin);
      iguanaDir = process.env.APPDATA + '/iguana';
      iguanaDir = path.normalize(iguanaDir);
      iguanaConfsDir = process.env.APPDATA + '/iguana/confs';
      iguanaConfsDir = path.normalize(iguanaConfsDir);
      iguanaIcon = path.join(__dirname, '/assets/icons/agama_icons/agama_app_icon.ico'),
      iguanaConfsDirSrc = path.normalize(iguanaConfsDirSrc);

      komododBin = path.join(__dirname, '../assets/bin/win64/komodod.exe'),
      komododBin = path.normalize(komododBin),
      komodocliBin = path.join(__dirname, '../assets/bin/win64/komodo-cli.exe'),
      komodocliBin = path.normalize(komodocliBin),
      komodoDir = process.env.APPDATA + '/Komodo',
      komodoDir = path.normalize(komodoDir);
}

shepherd.appConfig = {
  "edexGuiOnly": true,
  "iguanaGuiOnly": false,
  "manualIguanaStart": false,
  "skipBasiliskNetworkCheck": false,
  "minNotaries": 8,
  "host": "127.0.0.1",
  "iguanaAppPort": 17777,
  "iguanaCorePort": 7778,
  "maxDescriptors": {
    "darwin": 90000,
    "linux": 1000000
  },
  "killIguanaOnStart": true,
  "dev": false,
  "v2": false,
  "forks": {
    "basilisk": false,
    "all": false
  }
};

shepherd.quitKomodod = function(chain) {
  // exit komodod gracefully
  console.log('exec ' + komodocliBin + (chain ? ' ac_name=' + chain : '') + ' stop');
  exec(komodocliBin + (chain ? ' ac_name=' + chain : '') + ' stop', function(error, stdout, stderr) {
    console.log('stdout: ' + stdout)
    console.log('stderr: ' + stderr)
    if (error !== null) {
      console.log('exec error: ' + error)
    }
  });
}

shepherd.saveLocalAppConf = function(appSettings) {
  var appConfFileName = iguanaDir + '/config.json';

  var FixFilePermissions = function() {
    return new Promise(function(resolve, reject) {
      var result = 'config.json file permissions updated to Read/Write';

      fsnode.chmodSync(appConfFileName, '0666');

      setTimeout(function() {
        console.log(result);
        resolve(result);
      }, 1000);
    });
  }

  var FsWrite = function() {
    return new Promise(function(resolve, reject) {
      var result = 'config.json write file is done'

      fs.writeFile(appConfFileName,
                   JSON.stringify(appSettings)
                   .replace(/,/g, ',\n') // format json in human readable form
                   .replace(/:/g, ': ')
                   .replace(/{/g, '{\n')
                   .replace(/}/g, '\n}'), 'utf8', function(err) {
        if (err)
          return console.log(err);
      });

      fsnode.chmodSync(appConfFileName, '0666');
      setTimeout(function() {
        console.log(result);
        console.log('app conf.json file is created successfully at: ' + iguanaConfsDir);
        resolve(result);
      }, 2000);
    });
  }

  FsWrite()
  .then(FixFilePermissions());
}

shepherd.loadLocalConfig = function() {
  if (fs.existsSync(iguanaDir + '/config.json')) {
    var localAppConfig = fs.readFileSync(iguanaDir + '/config.json', 'utf8');
    console.log('app config set from local file');

    // find diff between local and hardcoded configs
    // append diff to local config
    var compareJSON = function(obj1, obj2) {
      var result = {};

      for (var i in obj1) {
        if (!obj2.hasOwnProperty(i)) {
          result[i] = obj1[i];
        }
      }

      return result;
    };

    if (localAppConfig) {
      var compareConfigs = compareJSON(shepherd.appConfig, JSON.parse(localAppConfig));
      if (Object.keys(compareConfigs).length) {
        var newConfig = Object.assign(JSON.parse(localAppConfig), compareConfigs);

        console.log('config diff is found, updating local config');
        console.log('config diff:');
        console.log(compareConfigs);

        shepherd.saveLocalAppConf(newConfig);
        return newConfig;
      } else {
        return JSON.parse(localAppConfig);
      }
    } else {
      return shepherd.appConfig;
    }
  } else {
    console.log('local config file is not found!');
    shepherd.saveLocalAppConf(shepherd.appConfig);

    return shepherd.appConfig;
  }
};

shepherd.appConfig = shepherd.loadLocalConfig();

console.log('iguana dir: ' + iguanaDir);
console.log('iguana bin: ' + iguanaBin);
console.log('--------------------------')
console.log('iguana dir: ' + komododBin);
console.log('iguana bin: ' + komodoDir);

// END IGUANA FILES AND CONFIG SETTINGS
shepherd.get('/', function(req, res, next) {
  res.send('Iguana app server');
});

shepherd.get('/appconf', function(req, res, next) {
  var obj = shepherd.loadLocalConfig();
  res.send(obj);
});

shepherd.get('/sysinfo', function(req, res, next) {
  var obj = shepherd.SystemInfo();
  res.send(obj);
});

shepherd.dumpCacheBeforeExit = function() {
  cache.dumpCacheBeforeExit();
}

var cache = require('./cache');
var mock = require('./mock');

// expose sockets obj
shepherd.setIO = function(io) {
  shepherd.io = io;
  cache.setVar('io', io);
};

cache.setVar('iguanaDir', iguanaDir);
cache.setVar('appConfig', shepherd.appConfig);

shepherd.getSyncOnlyForksInfo = function() {
  async.forEachOf(iguanaInstanceRegistry, function(data, port) {
    if (iguanaInstanceRegistry[port].mode.indexOf('/sync') > -1) {
      syncOnlyIguanaInstanceInfo[port] = {};
      request({
        url: 'http://localhost:' + port + '/api/bitcoinrpc/getinfo?userpass=<PASSWORD>Ig<PASSWORD>',
        method: 'GET'
      }, function (error, response, body) {
        if (response && response.statusCode && response.statusCode === 200) {
          console.log(body);
          try {
            syncOnlyIguanaInstanceInfo[port].getinfo = JSON.parse(body);
          } catch(e) {}
        } else {
          // TODO: error
        }
      });
      request({
        url: 'http://localhost:' + port + '/api/SuperNET/activehandle?userpass=<PASSWORD>IgRPCUser@1<PASSWORD>',
        method: 'GET'
      }, function (error, response, body) {
        if (response && response.statusCode && response.statusCode === 200) {
          console.log(body);
          try {
            syncOnlyIguanaInstanceInfo[port].activehandle = JSON.parse(body);
          } catch(e) {}
        } else {
          // TODO: error
        }
      });
    }
  });
}

shepherd.get('/forks/info/start', function(req, res, next) {
  var successObj = {
    'msg': 'success',
    'result': 'started'
  };

  res.end(JSON.stringify(successObj));
  shepherd.getSyncOnlyForksInfo();
});

shepherd.get('/forks/info/show', function(req, res, next) {
  var successObj = {
    'msg': 'success',
    'result': JSON.stringify(syncOnlyIguanaInstanceInfo)
  };

  res.end(JSON.stringify(successObj));
});

/*
 *  type: GET
 *<commit_msg>post app config(wip)<commit_after>const electron = require('electron'),
      app = electron.app,
      BrowserWindow = electron.BrowserWindow,
      path = require('path'),
      url = require('url'),
      os = require('os'),
      fsnode = require('fs'),
      fs = require('fs-extra'),
      _fs = require('graceful-fs'),
      mkdirp = require('mkdirp'),
      express = require('express'),
      exec = require('child_process').exec,
      spawn = require('child_process').spawn,
      md5 = require('md5'),
      pm2 = require('pm2'),
      request = require('request'),
      async = require('async'),
      rimraf = require('rimraf'),
      portscanner = require('portscanner'),
      Promise = require('bluebird');

const fixPath = require('fix-path');
var ps = require('ps-node'),
    setconf = require('../private/setconf.js'),
    //coincli = require('../private/coincli.js'),
    assetChainPorts = require('./ports.js')
    shepherd = express.Router(),
    iguanaInstanceRegistry = {},
    syncOnlyIguanaInstanceInfo = {},
    syncOnlyInstanceInterval = -1;

// IGUANA FILES AND CONFIG SETTINGS
var iguanaConfsDirSrc = path.join(__dirname, '../assets/deps/confs'),
    CorsProxyBin = path.join(__dirname, '../node_modules/corsproxy/bin/corsproxy');

// SETTING OS DIR TO RUN IGUANA FROM
// SETTING APP ICON FOR LINUX AND WINDOWS
if (os.platform() === 'darwin') {
  fixPath();
  var iguanaBin = path.join(__dirname, '../assets/bin/osx/iguana'),
      iguanaDir = process.env.HOME + '/Library/Application Support/iguana',
      iguanaConfsDir = iguanaDir + '/confs',
      komododBin = path.join(__dirname, '../assets/bin/osx/komodod'),
      komodocliBin = path.join(__dirname, '../assets/bin/osx/komodo-cli'),
      komodoDir = process.env.HOME + '/Library/Application Support/Komodo';

      zcashdBin = '/Applications/ZCashSwingWalletUI.app/Contents/MacOS/zcashd',
      zcashcliBin = '/Applications/ZCashSwingWalletUI.app/Contents/MacOS/zcash-cli',
      zcashDir = process.env.HOME + '/Library/Application Support/Zcash';
}

if (os.platform() === 'linux') {
  var iguanaBin = path.join(__dirname, '../assets/bin/linux64/iguana'),
      iguanaDir = process.env.HOME + '/.iguana',
      iguanaConfsDir = iguanaDir + '/confs',
      iguanaIcon = path.join(__dirname, '/assets/icons/agama_icons/128x128.png'),
      komododBin = path.join(__dirname, '../assets/bin/linux64/komodod'),
      komodocliBin = path.join(__dirname, '../assets/bin/linux64/komodo-cli'),
      komodoDir = process.env.HOME + '/.komodo';
}

if (os.platform() === 'win32') {
  var iguanaBin = path.join(__dirname, '../assets/bin/win64/iguana.exe');
      iguanaBin = path.normalize(iguanaBin);
      iguanaDir = process.env.APPDATA + '/iguana';
      iguanaDir = path.normalize(iguanaDir);
      iguanaConfsDir = process.env.APPDATA + '/iguana/confs';
      iguanaConfsDir = path.normalize(iguanaConfsDir);
      iguanaIcon = path.join(__dirname, '/assets/icons/agama_icons/agama_app_icon.ico'),
      iguanaConfsDirSrc = path.normalize(iguanaConfsDirSrc);

      komododBin = path.join(__dirname, '../assets/bin/win64/komodod.exe'),
      komododBin = path.normalize(komododBin),
      komodocliBin = path.join(__dirname, '../assets/bin/win64/komodo-cli.exe'),
      komodocliBin = path.normalize(komodocliBin),
      komodoDir = process.env.APPDATA + '/Komodo',
      komodoDir = path.normalize(komodoDir);
}

shepherd.appConfig = {
  "edexGuiOnly": true,
  "iguanaGuiOnly": false,
  "manualIguanaStart": false,
  "skipBasiliskNetworkCheck": false,
  "minNotaries": 8,
  "host": "127.0.0.1",
  "iguanaAppPort": 17777,
  "iguanaCorePort": 7778,
  "maxDescriptors": {
    "darwin": 90000,
    "linux": 1000000
  },
  "killIguanaOnStart": true,
  "dev": false,
  "v2": false,
  "forks": {
    "basilisk": false,
    "all": false
  }
};

shepherd.quitKomodod = function(chain) {
  // exit komodod gracefully
  console.log('exec ' + komodocliBin + (chain ? ' ac_name=' + chain : '') + ' stop');
  exec(komodocliBin + (chain ? ' ac_name=' + chain : '') + ' stop', function(error, stdout, stderr) {
    console.log('stdout: ' + stdout)
    console.log('stderr: ' + stderr)
    if (error !== null) {
      console.log('exec error: ' + error)
    }
  });
}

/*
 *  type: POST
 *  params: payload
 */
shepherd.post('/appconf', function(req, res, next) {
  if (!req.body.payload) {
    const errorObj = {
      'msg': 'error',
      'result': 'no payload provided'
    };

    res.end(JSON.stringify(errorObj));
  } else {
    shepherd.saveLocalAppConf(req.body.payload);

    const errorObj = {
      'msg': 'success',
      'result': 'config saved'
    };

    res.end(JSON.stringify(errorObj));
  }
});

shepherd.saveLocalAppConf = function(appSettings) {
  var appConfFileName = iguanaDir + '/config.json';

  var FixFilePermissions = function() {
    return new Promise(function(resolve, reject) {
      var result = 'config.json file permissions updated to Read/Write';

      fsnode.chmodSync(appConfFileName, '0666');

      setTimeout(function() {
        console.log(result);
        resolve(result);
      }, 1000);
    });
  }

  var FsWrite = function() {
    return new Promise(function(resolve, reject) {
      var result = 'config.json write file is done'

      fs.writeFile(appConfFileName,
                   JSON.stringify(appSettings)
                   .replace(/,/g, ',\n') // format json in human readable form
                   .replace(/:/g, ': ')
                   .replace(/{/g, '{\n')
                   .replace(/}/g, '\n}'), 'utf8', function(err) {
        if (err)
          return console.log(err);
      });

      fsnode.chmodSync(appConfFileName, '0666');
      setTimeout(function() {
        console.log(result);
        console.log('app conf.json file is created successfully at: ' + iguanaConfsDir);
        resolve(result);
      }, 2000);
    });
  }

  FsWrite()
  .then(FixFilePermissions());
}

shepherd.loadLocalConfig = function() {
  if (fs.existsSync(iguanaDir + '/config.json')) {
    var localAppConfig = fs.readFileSync(iguanaDir + '/config.json', 'utf8');
    console.log('app config set from local file');

    // find diff between local and hardcoded configs
    // append diff to local config
    var compareJSON = function(obj1, obj2) {
      var result = {};

      for (var i in obj1) {
        if (!obj2.hasOwnProperty(i)) {
          result[i] = obj1[i];
        }
      }

      return result;
    };

    if (localAppConfig) {
      var compareConfigs = compareJSON(shepherd.appConfig, JSON.parse(localAppConfig));
      if (Object.keys(compareConfigs).length) {
        var newConfig = Object.assign(JSON.parse(localAppConfig), compareConfigs);

        console.log('config diff is found, updating local config');
        console.log('config diff:');
        console.log(compareConfigs);

        shepherd.saveLocalAppConf(newConfig);
        return newConfig;
      } else {
        return JSON.parse(localAppConfig);
      }
    } else {
      return shepherd.appConfig;
    }
  } else {
    console.log('local config file is not found!');
    shepherd.saveLocalAppConf(shepherd.appConfig);

    return shepherd.appConfig;
  }
};

shepherd.appConfig = shepherd.loadLocalConfig();

console.log('iguana dir: ' + iguanaDir);
console.log('iguana bin: ' + iguanaBin);
console.log('--------------------------')
console.log('iguana dir: ' + komododBin);
console.log('iguana bin: ' + komodoDir);

// END IGUANA FILES AND CONFIG SETTINGS
shepherd.get('/', function(req, res, next) {
  res.send('Iguana app server');
});

shepherd.get('/appconf', function(req, res, next) {
  var obj = shepherd.loadLocalConfig();
  res.send(obj);
});

shepherd.get('/sysinfo', function(req, res, next) {
  var obj = shepherd.SystemInfo();
  res.send(obj);
});

shepherd.dumpCacheBeforeExit = function() {
  cache.dumpCacheBeforeExit();
}

var cache = require('./cache');
var mock = require('./mock');

// expose sockets obj
shepherd.setIO = function(io) {
  shepherd.io = io;
  cache.setVar('io', io);
};

cache.setVar('iguanaDir', iguanaDir);
cache.setVar('appConfig', shepherd.appConfig);

// fetch sync only forks info
shepherd.getSyncOnlyForksInfo = function() {
  async.forEachOf(iguanaInstanceRegistry, function(data, port) {
    if (iguanaInstanceRegistry[port].mode.indexOf('/sync') > -1) {
      syncOnlyIguanaInstanceInfo[port] = {};
      request({
        url: 'http://localhost:' + port + '/api/bitcoinrpc/getinfo?userpass=<PASSWORD>',
        method: 'GET'
      }, function (error, response, body) {
        if (response && response.statusCode && response.statusCode === 200) {
          console.log(body);
          try {
            syncOnlyIguanaInstanceInfo[port].getinfo = JSON.parse(body);
          } catch(e) {}
        } else {
          // TODO: error
        }
      });
      request({
        url: 'http://localhost:' + port + '/api/SuperNET/activehandle?userpass=<PASSWORD>',
        method: 'GET'
      }, function (error, response, body) {
        if (response && response.statusCode && response.statusCode === 200) {
          console.log(body);
          try {
            syncOnlyIguanaInstanceInfo[port].activehandle = JSON.parse(body);
          } catch(e) {}
        } else {
          // TODO: error
        }
      });
    }
  });
}

/*
 *  type: GET
 *
 */
shepherd.get('/forks/info/start', function(req, res, next) {
  var successObj = {
    'msg': 'success',
    'result': 'started'
  };

  res.end(JSON.stringify(successObj));
  shepherd.getSyncOnlyForksInfo();
});

/*
 *  type: GET
 *
 */
shepherd.get('/forks/info/show', function(req, res, next) {
  var successObj = {
    'msg': 'success',
    'result': JSON.stringify(syncOnlyIguanaInstanceInfo)
  };

  res.end(JSON.stringify(successObj));
});

/*
 *  type: GET
 *
{'fraction_non_alphanumeric': 0.1630041432842083, 'fraction_numerical': 0.008863481407667698, 'mean_word_length': 2.9429280397022333, 'pattern_counts': {'":': 34, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1311314', 'n_tokens_mistral': 6442, 'n_tokens_neox': 6192, 'n_words': 1152}