Skip to content
This repository has been archived by the owner on Jul 22, 2020. It is now read-only.

Commit

Permalink
feat: install and run replicator cli
Browse files Browse the repository at this point in the history
  • Loading branch information
mvines committed Jun 29, 2019
1 parent 4e84d68 commit ff87cc6
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 12 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@
"electron-squirrel-startup": "^1.0.0",
"immutable": "^4.0.0-rc.12",
"javascript-terminal": "^1.0.3",
"jsonfile": "^5.0.0",
"node-fetch": "^2.6.0",
"npm-run-all": "^4.1.5",
"promisify-child-process": "^3.1.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-hot-loader": "^4.11.1",
Expand Down
31 changes: 21 additions & 10 deletions src/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {ReactThemes, ReactTerminal} from 'react-terminal-component';
import {EmulatorState, OutputFactory, Outputs} from 'javascript-terminal';

import {url} from './url';
import {Replicator} from './replicator';

const styles = theme => ({
root: {
Expand Down Expand Up @@ -60,6 +61,9 @@ class App extends React.Component {

this.clearTerminal();
this.addTerminalText(`Cluster entrypoint: ${url}...`);

this.replicator = new Replicator(this.connection, this);
this.replicator.start();
}

componentDidMount() {
Expand Down Expand Up @@ -90,18 +94,22 @@ class App extends React.Component {
}

addTerminalText(text) {
this.terminalOutputs = Outputs.addRecord(
this.terminalOutputs,
OutputFactory.makeTextOutput(text),
);
text.split('\n').forEach(line => {
this.terminalOutputs = Outputs.addRecord(
this.terminalOutputs,
OutputFactory.makeTextOutput(line),
);
});
this.trimTerminalOutput();
}

addTerminalError(errorMessage) {
this.terminalOutputs = Outputs.addRecord(
this.terminalOutputs,
OutputFactory.makeErrorOutput({source: 'error', type: errorMessage}),
);
errorMessage.split('\n').forEach(line => {
this.terminalOutputs = Outputs.addRecord(
this.terminalOutputs,
OutputFactory.makeErrorOutput({source: 'error', type: line}),
);
});
this.trimTerminalOutput();
}

Expand All @@ -114,15 +122,18 @@ class App extends React.Component {

clusterRestart() {
this.addTerminalText(`Cluster restart detected at ${new Date()}`);
this.replicator.restart();
}

async updateClusterStats() {
try {
const transactionCount = await this.connection.getTransactionCount();
const totalSupply = await this.connection.getTotalSupply();

if (transactionCount < this.state.transactionCount) {
this.addTerminalText(`Transaction count decreased from ${this.state.transactionCount} to ${transactionCount}`);
if (transactionCount < this.state.transactionCount / 2) {
this.addTerminalText(
`Transaction count decreased from ${this.state.transactionCount} to ${transactionCount}`,
);
this.clusterRestart();
}

Expand Down
145 changes: 145 additions & 0 deletions src/replicator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import log from 'electron-log';
import {spawn} from 'promisify-child-process';
import path from 'path';
import electron from 'electron';
import jsonfile from 'jsonfile';
import {Account} from '@solana/web3.js';
import {solanaInstallInit} from './solana-install-init';

export class Replicator {
constructor(connection, terminalOutput) {
this.connection = connection;
this.terminalOutput = terminalOutput;
this.running = false;

const userDataPath = electron.remote.app.getPath('userData');
this.solanaInstallBinDir = path.join(
userDataPath,
'install',
'active_release',
'bin',
);
this.replicatorKeypairFile = path.join(
userDataPath,
'replicator-keypair.json',
);
this.storageKeypairFile = path.join(userDataPath, 'storage-keypair.json');
this.replicatorKeypairDir = path.join(userDataPath, 'ledger');

this.solanaInstallConfig = path.join(userDataPath, 'config.yml');
this.solanaInstallDataDir = path.join(userDataPath, 'install');
}

start() {
if (this.running) {
log.warn('Replicator already running, ignoring start()');
return;
}
this.running = true;
this.main();
}

stop() {
if (!this.running) {
return;
}
this.terminalOutput.addTerminalText('^C');
this.running = false;
// TODO: signal main to exit...
}

restart() {
if (!this.running) {
return;
}
this.stop();
this.start();
}

/**
* @private
*/
async cmd(command, args) {
this.terminalOutput.addTerminalCommand(`${command} ${args.join(' ')}`);
const child = spawn(command, args);

child.stdout.on('data', data =>
this.terminalOutput.addTerminalText(data.toString()),
);
child.stderr.on('data', data =>
this.terminalOutput.addTerminalError(data.toString()),
);
return child;
}

/**
* @private
*/
async main() {
const solanaInstall = `${this.solanaInstallBinDir}/solana-install`;
const solanaKeygen = `${this.solanaInstallBinDir}/solana-keygen`;
const solanaWallet = `${this.solanaInstallBinDir}/solana-wallet`;

try {
await this.cmd(solanaInstallInit, [
'--config',
this.solanaInstallConfig,
'--data-dir',
this.solanaInstallDataDir,
'--no-modify-path',
]);
await this.cmd(solanaKeygen, [
'new',
'-f',
'-o',
this.replicatorKeypairFile,
]);
await this.cmd(solanaWallet, [
'--keypair',
this.replicatorKeypairFile,
'airdrop',
'100000',
]);

await this.cmd(solanaKeygen, [
'new',
'-f',
'-o',
this.storageKeypairFile,
]);

const replicatorKeypair = new Account(
Buffer.from(jsonfile.readFileSync(this.replicatorKeypairFile)),
);
const storageKeypair = new Account(
Buffer.from(jsonfile.readFileSync(this.storageKeypairFile)),
);

await this.cmd(solanaWallet, [
'--keypair',
this.replicatorKeypairFile,
'create-replicator-storage-account',
replicatorKeypair.publicKey.toString(),
storageKeypair.publicKey.toString(),
]);

await this.cmd(solanaInstall, [
'--config',
this.solanaInstallConfig,
'run',
'solana-replicator',
'--',
'--entrypoint',
'testnet.solana.com:8001',
'--identity',
this.replicatorKeypairFile,
'--storage-keypair',
this.storageKeypairFile,
'--ledger',
this.replicatorLedgerDir,
]);
} catch (err) {
this.terminalOutput.addTerminalError(err.message);
}
}
}
20 changes: 18 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.5.tgz#04af8d5d5a2b044a2a1bffacc1e5e6673544e872"
integrity sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==

"@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.5":
"@babel/runtime@^7.1.2", "@babel/runtime@^7.1.5", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.5":
version "7.4.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.5.tgz#582bb531f5f9dc67d2fcb682979894f75e253f12"
integrity sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==
Expand Down Expand Up @@ -6695,6 +6695,15 @@ jsonfile@^4.0.0:
optionalDependencies:
graceful-fs "^4.1.6"

jsonfile@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-5.0.0.tgz#e6b718f73da420d612823996fdf14a03f6ff6922"
integrity sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==
dependencies:
universalify "^0.1.2"
optionalDependencies:
graceful-fs "^4.1.6"

jsonify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
Expand Down Expand Up @@ -9336,6 +9345,13 @@ promise@~2.0:
dependencies:
is-promise "~1"

promisify-child-process@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/promisify-child-process/-/promisify-child-process-3.1.0.tgz#dbd9cf5978d24a921cfeed36c9cfd894ce77387b"
integrity sha512-qSXQUk7eci66DGQ62Joo5k8Li5x+WsloaM+oPPeKY549suS4ZIvi/qj2POsLlsG8a6RzBSZezvYHw75mcn7WmQ==
dependencies:
"@babel/runtime" "^7.1.5"

promzard@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee"
Expand Down Expand Up @@ -11509,7 +11525,7 @@ universal-user-agent@^2.0.0, universal-user-agent@^2.1.0:
dependencies:
os-name "^3.0.0"

universalify@^0.1.0:
universalify@^0.1.0, universalify@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
Expand Down

0 comments on commit ff87cc6

Please sign in to comment.