2018-11-30 17:33:29 -08:00
|
|
|
// @flow
|
2019-02-04 20:41:45 -08:00
|
|
|
|
2018-11-30 17:33:29 -08:00
|
|
|
import cp from 'child_process';
|
|
|
|
import path from 'path';
|
2018-12-04 11:13:16 -08:00
|
|
|
import os from 'os';
|
2019-04-08 09:24:37 -07:00
|
|
|
import fs from 'fs';
|
2018-11-30 17:33:29 -08:00
|
|
|
import processExists from 'process-exists';
|
2018-12-05 08:34:49 -08:00
|
|
|
/* eslint-disable import/no-extraneous-dependencies */
|
2018-11-30 21:21:12 -08:00
|
|
|
import isDev from 'electron-is-dev';
|
2018-11-30 17:33:29 -08:00
|
|
|
import type { ChildProcess } from 'child_process';
|
2018-12-03 18:34:41 -08:00
|
|
|
import eres from 'eres';
|
2019-01-29 13:35:22 -08:00
|
|
|
import uuid from 'uuid/v4';
|
2019-03-01 15:27:42 -08:00
|
|
|
import findProcess from 'find-process';
|
2019-03-30 14:10:38 -07:00
|
|
|
|
2018-12-05 08:34:49 -08:00
|
|
|
/* eslint-disable-next-line import/named */
|
|
|
|
import { mainWindow } from '../electron';
|
2019-03-24 11:57:13 -07:00
|
|
|
import waitForDaemonClose from './wait-for-daemon-close';
|
2018-11-30 17:33:29 -08:00
|
|
|
import getBinariesPath from './get-binaries-path';
|
2018-11-30 21:21:12 -08:00
|
|
|
import getOsFolder from './get-os-folder';
|
2018-11-30 17:33:29 -08:00
|
|
|
import getDaemonName from './get-daemon-name';
|
|
|
|
import fetchParams from './run-fetch-params';
|
2019-04-08 09:24:37 -07:00
|
|
|
import { locateZcashConf } from './locate-zcash-conf';
|
2019-05-02 20:38:30 -07:00
|
|
|
import { log } from './logger';
|
2018-12-05 11:43:47 -08:00
|
|
|
import store from '../electron-store';
|
2019-03-07 11:15:41 -08:00
|
|
|
import { parseZcashConf, parseCmdArgs, generateArgsFromConf } from './parse-zcash-conf';
|
2019-03-16 20:25:16 -07:00
|
|
|
import { isTestnet } from '../is-testnet';
|
|
|
|
import {
|
|
|
|
EMBEDDED_DAEMON,
|
|
|
|
ZCASH_NETWORK,
|
|
|
|
TESTNET,
|
|
|
|
MAINNET,
|
|
|
|
} from '../../app/constants/zcash-network';
|
2018-11-30 17:33:29 -08:00
|
|
|
|
2019-04-08 09:24:37 -07:00
|
|
|
const getDaemonOptions = ({
|
|
|
|
username, password, useDefaultZcashConf, optionsFromZcashConf,
|
|
|
|
}) => {
|
2018-12-04 08:29:16 -08:00
|
|
|
/*
|
|
|
|
-showmetrics
|
|
|
|
Show metrics on stdout
|
|
|
|
-metricsui
|
|
|
|
Set to 1 for a persistent metrics screen, 0 for sequential metrics
|
|
|
|
output
|
|
|
|
-metricsrefreshtime
|
|
|
|
Number of seconds between metrics refreshes
|
|
|
|
*/
|
2019-03-19 18:28:35 -07:00
|
|
|
|
2018-12-05 11:43:47 -08:00
|
|
|
const defaultOptions = [
|
2019-04-08 09:24:37 -07:00
|
|
|
'-server=1',
|
2018-12-05 11:43:47 -08:00
|
|
|
'-showmetrics',
|
|
|
|
'--metricsui=0',
|
2019-01-02 11:18:15 -08:00
|
|
|
'-metricsrefreshtime=1',
|
2018-12-05 11:43:47 -08:00
|
|
|
`-rpcuser=${username}`,
|
|
|
|
`-rpcpassword=${password}`,
|
2019-03-19 18:28:35 -07:00
|
|
|
...(isTestnet() ? ['-testnet', '-addnode=testnet.z.cash'] : ['-addnode=mainnet.z.cash']),
|
2019-02-04 08:12:04 -08:00
|
|
|
// Overwriting the settings with values taken from "zcash.conf"
|
|
|
|
...optionsFromZcashConf,
|
2018-12-05 11:43:47 -08:00
|
|
|
];
|
2019-02-04 08:12:04 -08:00
|
|
|
|
2019-04-08 09:24:37 -07:00
|
|
|
if (useDefaultZcashConf) defaultOptions.push(`-conf=${locateZcashConf()}`);
|
|
|
|
|
2019-03-16 20:25:16 -07:00
|
|
|
return Array.from(new Set([...defaultOptions, ...optionsFromZcashConf]));
|
2018-12-04 08:29:16 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
let resolved = false;
|
2018-11-30 21:21:12 -08:00
|
|
|
|
2019-03-01 15:27:42 -08:00
|
|
|
const ZCASHD_PROCESS_NAME = getDaemonName();
|
|
|
|
|
2019-05-07 20:40:07 -07:00
|
|
|
let isWindowOpened = false;
|
|
|
|
|
|
|
|
const sendToRenderer = (event: string, message: Object, shouldLog: boolean = true) => {
|
|
|
|
if (shouldLog) {
|
|
|
|
log(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isWindowOpened) {
|
|
|
|
if (!mainWindow.isDestroyed()) {
|
|
|
|
mainWindow.webContents.send(event, message);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const interval = setInterval(() => {
|
|
|
|
if (isWindowOpened) {
|
|
|
|
mainWindow.webContents.send(event, message);
|
|
|
|
clearInterval(interval);
|
|
|
|
}
|
|
|
|
}, 1000);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-12-15 07:10:39 -08:00
|
|
|
// eslint-disable-next-line
|
2018-12-03 18:34:41 -08:00
|
|
|
const runDaemon: () => Promise<?ChildProcess> = () => new Promise(async (resolve, reject) => {
|
2019-05-07 20:40:07 -07:00
|
|
|
mainWindow.webContents.on('dom-ready', () => {
|
|
|
|
isWindowOpened = true;
|
|
|
|
});
|
2019-05-13 18:18:52 -07:00
|
|
|
store.delete('rpcport');
|
2019-05-07 20:40:07 -07:00
|
|
|
|
2019-03-01 15:27:42 -08:00
|
|
|
const processName = path.join(getBinariesPath(), getOsFolder(), ZCASHD_PROCESS_NAME);
|
2019-04-15 20:15:46 -07:00
|
|
|
const isRelaunch = Boolean(process.argv.find(arg => arg === '--relaunch'));
|
2018-11-30 17:33:29 -08:00
|
|
|
|
2019-02-04 16:32:53 -08:00
|
|
|
if (!mainWindow.isDestroyed()) mainWindow.webContents.send('zcashd-params-download', 'Fetching params...');
|
|
|
|
|
2019-05-07 20:40:07 -07:00
|
|
|
sendToRenderer('zcash-daemon-status', {
|
|
|
|
error: false,
|
|
|
|
status:
|
|
|
|
'Downloading network params, this may take some time depending on your connection speed',
|
|
|
|
});
|
|
|
|
|
2018-12-03 18:34:41 -08:00
|
|
|
const [err] = await eres(fetchParams());
|
|
|
|
|
|
|
|
if (err) {
|
2019-05-07 20:40:07 -07:00
|
|
|
sendToRenderer('zcash-daemon-status', {
|
|
|
|
error: true,
|
|
|
|
status: `Error while fetching params: ${err.message}`,
|
|
|
|
});
|
|
|
|
|
2018-12-03 18:34:41 -08:00
|
|
|
return reject(new Error(err));
|
|
|
|
}
|
|
|
|
|
2019-05-07 20:40:07 -07:00
|
|
|
sendToRenderer('zcash-daemon-status', {
|
|
|
|
error: false,
|
|
|
|
status: 'Zepio Starting',
|
|
|
|
});
|
2018-12-03 18:34:41 -08:00
|
|
|
|
2019-03-24 11:57:13 -07:00
|
|
|
// In case of --relaunch on argv, we need wait to close the old zcash daemon
|
|
|
|
// a workaround is use a interval to check if there is a old process running
|
2019-04-15 20:15:46 -07:00
|
|
|
if (isRelaunch) {
|
2019-03-24 11:57:13 -07:00
|
|
|
await waitForDaemonClose(ZCASHD_PROCESS_NAME);
|
|
|
|
}
|
|
|
|
|
2019-03-01 15:27:42 -08:00
|
|
|
const [, isRunning] = await eres(processExists(ZCASHD_PROCESS_NAME));
|
|
|
|
|
|
|
|
// This will parse and save rpcuser and rpcpassword in the store
|
2019-04-08 09:24:37 -07:00
|
|
|
let [, optionsFromZcashConf] = await eres(parseZcashConf());
|
|
|
|
|
|
|
|
// if the user has a custom datadir and doesn't have a zcash.conf in that folder,
|
|
|
|
// we need to use the default zcash.conf
|
|
|
|
let useDefaultZcashConf = false;
|
|
|
|
|
|
|
|
if (optionsFromZcashConf.datadir) {
|
|
|
|
const hasDatadirConf = fs.existsSync(path.join(optionsFromZcashConf.datadir, 'zcash.conf'));
|
|
|
|
|
|
|
|
if (hasDatadirConf) {
|
|
|
|
optionsFromZcashConf = await parseZcashConf(
|
|
|
|
path.join(String(optionsFromZcashConf.datadir), 'zcash.conf'),
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
useDefaultZcashConf = true;
|
|
|
|
}
|
|
|
|
}
|
2019-03-07 11:15:41 -08:00
|
|
|
|
2019-05-13 18:18:52 -07:00
|
|
|
if (optionsFromZcashConf.rpcport) store.set('rpcport', optionsFromZcashConf.rpcport);
|
2019-03-07 11:15:41 -08:00
|
|
|
if (optionsFromZcashConf.rpcuser) store.set('rpcuser', optionsFromZcashConf.rpcuser);
|
|
|
|
if (optionsFromZcashConf.rpcpassword) store.set('rpcpassword', optionsFromZcashConf.rpcpassword);
|
2018-12-03 18:34:41 -08:00
|
|
|
|
|
|
|
if (isRunning) {
|
|
|
|
log('Already is running!');
|
2019-03-16 20:25:16 -07:00
|
|
|
|
|
|
|
store.set(EMBEDDED_DAEMON, false);
|
2019-03-01 15:27:42 -08:00
|
|
|
// We need grab the rpcuser and rpcpassword from either process args or zcash.conf
|
|
|
|
|
|
|
|
// Command line args override zcash.conf
|
|
|
|
const [{ cmd }] = await findProcess('name', ZCASHD_PROCESS_NAME);
|
2019-05-13 18:18:52 -07:00
|
|
|
const {
|
|
|
|
user, password, port, isTestnet: isTestnetFromCmd,
|
|
|
|
} = parseCmdArgs(cmd);
|
2019-03-16 20:25:16 -07:00
|
|
|
|
|
|
|
store.set(
|
|
|
|
ZCASH_NETWORK,
|
|
|
|
isTestnetFromCmd || optionsFromZcashConf.testnet === '1' ? TESTNET : MAINNET,
|
|
|
|
);
|
|
|
|
|
2019-03-01 15:27:42 -08:00
|
|
|
if (user) store.set('rpcuser', user);
|
|
|
|
if (password) store.set('rpcpassword', password);
|
2019-05-13 18:18:52 -07:00
|
|
|
if (port) store.set('rpcport', port);
|
2019-03-01 15:27:42 -08:00
|
|
|
|
2018-12-03 18:34:41 -08:00
|
|
|
return resolve();
|
|
|
|
}
|
|
|
|
|
2019-03-19 18:28:35 -07:00
|
|
|
store.set(EMBEDDED_DAEMON, true);
|
|
|
|
|
2019-04-15 20:15:46 -07:00
|
|
|
if (!isRelaunch) {
|
|
|
|
store.set(ZCASH_NETWORK, optionsFromZcashConf.testnet === '1' ? TESTNET : MAINNET);
|
|
|
|
}
|
2019-03-19 18:28:35 -07:00
|
|
|
|
2019-03-07 11:15:41 -08:00
|
|
|
if (!optionsFromZcashConf.rpcuser) store.set('rpcuser', uuid());
|
|
|
|
if (!optionsFromZcashConf.rpcpassword) store.set('rpcpassword', uuid());
|
2018-12-05 11:43:47 -08:00
|
|
|
|
2019-03-07 11:15:41 -08:00
|
|
|
const rpcCredentials = {
|
|
|
|
username: store.get('rpcuser'),
|
|
|
|
password: store.get('rpcpassword'),
|
|
|
|
};
|
2018-12-05 11:43:47 -08:00
|
|
|
|
2019-01-08 06:34:20 -08:00
|
|
|
if (isDev) log('Rpc Credentials', rpcCredentials);
|
|
|
|
|
2019-02-04 08:34:58 -08:00
|
|
|
const childProcess = cp.spawn(
|
|
|
|
processName,
|
2019-04-08 09:24:37 -07:00
|
|
|
getDaemonOptions({
|
2019-03-07 11:15:41 -08:00
|
|
|
...rpcCredentials,
|
2019-04-08 09:24:37 -07:00
|
|
|
useDefaultZcashConf,
|
2019-03-07 11:15:41 -08:00
|
|
|
optionsFromZcashConf: generateArgsFromConf(optionsFromZcashConf),
|
|
|
|
}),
|
2019-02-04 08:34:58 -08:00
|
|
|
{
|
|
|
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
|
|
},
|
|
|
|
);
|
2018-12-03 18:34:41 -08:00
|
|
|
|
2018-12-05 08:34:49 -08:00
|
|
|
childProcess.stdout.on('data', (data) => {
|
2019-05-07 20:40:07 -07:00
|
|
|
sendToRenderer('zcashd-log', data.toString(), false);
|
2018-12-04 08:29:16 -08:00
|
|
|
if (!resolved) {
|
|
|
|
resolve(childProcess);
|
|
|
|
resolved = true;
|
|
|
|
}
|
2018-12-03 18:34:41 -08:00
|
|
|
});
|
|
|
|
|
|
|
|
childProcess.stderr.on('data', (data) => {
|
|
|
|
log(data.toString());
|
|
|
|
reject(new Error(data.toString()));
|
|
|
|
});
|
|
|
|
|
|
|
|
childProcess.on('error', reject);
|
2018-12-04 11:13:16 -08:00
|
|
|
|
|
|
|
if (os.platform() === 'win32') {
|
|
|
|
resolved = true;
|
|
|
|
resolve(childProcess);
|
|
|
|
}
|
2018-11-30 17:33:29 -08:00
|
|
|
});
|
|
|
|
|
2019-02-04 20:41:45 -08:00
|
|
|
// eslint-disable-next-line
|
2018-11-30 17:33:29 -08:00
|
|
|
export default runDaemon;
|