Skip to content

Commit

Permalink
feat(neotracker): add neotracker command to neo-one build (#1870)
Browse files Browse the repository at this point in the history
  • Loading branch information
afragapane authored Nov 20, 2019
1 parent a82552e commit 9a3e32a
Show file tree
Hide file tree
Showing 28 changed files with 2,073 additions and 116 deletions.
4 changes: 4 additions & 0 deletions packages/neo-one-cli-common-node/src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const configurationDefaults = {
neotracker: {
path: nodePath.join('.neo-one', 'neotracker'),
port: 9041,
skip: false,
},
};

Expand Down Expand Up @@ -135,6 +136,7 @@ const configurationSchema = {
properties: {
path: { type: 'string' },
port: { type: 'number', multipleOf: 1.0, minimum: 0 },
skip: { type: 'boolean' },
},
},
},
Expand Down Expand Up @@ -212,6 +214,8 @@ ${exportConfig} {
path: '${config.neotracker.path}',
// NEO•ONE will start an instance of NEO tracker using this port.
port: 9041,
// Set to true if you'd like NEO•ONE to skip starting a NEO tracker instance when running 'neo-one build'.
skip: false,
}
};
`;
Expand Down
1 change: 1 addition & 0 deletions packages/neo-one-cli-common/src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface NetworksConfiguration {
export interface NEOTrackerConfiguration {
readonly path: string;
readonly port: number;
readonly skip: boolean;
}

export interface MigrationConfiguration {
Expand Down
1 change: 1 addition & 0 deletions packages/neo-one-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"dependencies": {
"@babel/core": "^7.5.5",
"@babel/register": "^7.5.5",
"@neotracker/core": "^1.3.0",
"@neo-one/cli-common": "^2.3.0",
"@neo-one/cli-common-node": "^2.3.0",
"@neo-one/client-common": "^2.3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ module.exports = {
neotracker: {
path: nodePath.join(tmpDir, 'neotracker'),
port: neotrackerPort,
skip: false,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ module.exports = {
neotracker: {
path: nodePath.join(tmpDir, 'neotracker'),
port: neotrackerPort,
skip: true,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ module.exports = {
neotracker: {
path: nodePath.join(tmpDir, 'neotracker'),
port: neotrackerPort,
skip: true,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ module.exports = {
neotracker: {
path: nodePath.join(tmpDir, 'neotracker'),
port: neotrackerPort,
skip: true,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ module.exports = {
neotracker: {
path: nodePath.join(tmpDir, 'neotracker'),
port: neotrackerPort,
skip: true,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ module.exports = {
neotracker: {
path: nodePath.join(tmpDir, 'neotracker'),
port: neotrackerPort,
skip: false,
},
};
25 changes: 25 additions & 0 deletions packages/neo-one-cli/src/__e2e__/cmd/start/neotracker.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import fetch from 'cross-fetch';
import { isRunning } from '../../../common';

describe('start network', () => {
it('starts a private network', async () => {
const execAsync = one.createExecAsync('ico');
execAsync('start network');
const config = await one.getProjectConfig('ico');

await one.until(async () => {
const [live, ready] = await Promise.all([
fetch(`http://localhost:${config.network.port}/live_health_check`),
fetch(`http://localhost:${config.network.port}/ready_health_check`),
]);
expect(live.ok).toEqual(true);
expect(ready.ok).toEqual(true);
});

execAsync('start neotracker');
await one.until(async () => {
const live = await isRunning(config.neotracker.port);
expect(live).toEqual(true);
});
});
});
35 changes: 35 additions & 0 deletions packages/neo-one-cli/src/__e2e__/cmd/stop/neotracker.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import fetch from 'cross-fetch';
import { isRunning } from '../../../common';

describe('start network', () => {
it('starts a private network', async () => {
const execAsync = one.createExecAsync('ico');
execAsync('start network');
const config = await one.getProjectConfig('ico');

await one.until(async () => {
const [live, ready] = await Promise.all([
fetch(`http://localhost:${config.network.port}/live_health_check`),
fetch(`http://localhost:${config.network.port}/ready_health_check`),
]);
expect(live.ok).toEqual(true);
expect(ready.ok).toEqual(true);
});

execAsync('start neotracker');

await one.until(async () => {
const live = await isRunning(config.neotracker.port);
expect(live).toEqual(true);
});

await one.createExec('ico')('stop neotracker');
let success = false;
try {
success = await isRunning(config.neotracker.port);
} catch {
// do nothing
}
expect(success).toEqual(false);
});
});
10 changes: 10 additions & 0 deletions packages/neo-one-cli/src/build/createTasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { findContracts } from './findContracts';
import { generateCode } from './generateCode';
import { generateCommonCode } from './generateCommonCode';
import { setupWallets } from './setupWallets';
import { startNeotracker } from './startNeotracker';
import { startNetwork } from './startNetwork';

export const createTasks = (cmd: Command, config: Configuration, reset: boolean) =>
Expand Down Expand Up @@ -95,4 +96,13 @@ export const createTasks = (cmd: Command, config: Configuration, reset: boolean)
await generateCommonCode(config, ctx.contracts, networks, ctx.sourceMaps);
},
},
{
title: 'Start NEO tracker instance',
task: async (_ctx, task) => {
if (config.neotracker.skip) {
task.skip('NEO tracker instance skipped.');
}
await startNeotracker(cmd, config, reset);
},
},
]);
44 changes: 44 additions & 0 deletions packages/neo-one-cli/src/build/startNeotracker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Configuration } from '@neo-one/cli-common';
import execa from 'execa';
import { isRunning } from '../common';
import { Command } from '../types';
import { findKillProcess } from '../utils';

export const startNeotracker = async (cmd: Command, config: Configuration, reset: boolean) => {
const args = cmd.args.concat(['start', 'neotracker']);
if (reset) {
await findKillProcess('neotracker', config);
}

const proc = execa(cmd.bin, reset ? args.concat(['--reset']) : args, {
cleanup: false,
detached: true,
stdio: 'ignore',
});
proc.unref();

const start = Date.now();
const timeoutMS = 30 * 1000;
let ready = false;
if (reset) {
await new Promise((resolve) => setTimeout(resolve, 3000));
}
// tslint:disable-next-line no-loop-statement
while (Date.now() - start < timeoutMS) {
try {
const response = await isRunning(config.neotracker.port);
if (response) {
ready = true;
break;
}
} catch {
// do nothing
}

await new Promise((resolve) => setTimeout(resolve, 500));
}

if (!ready) {
throw new Error('Neotracker is not ready.');
}
};
3 changes: 2 additions & 1 deletion packages/neo-one-cli/src/cmd/start/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import yargs from 'yargs';
import * as neotracker from './neotracker';
import * as network from './network';

export const command = 'start';
export const describe = 'Start NEO•ONE services.';
export const builder = (yargsBuilder: typeof yargs) => yargsBuilder.command(network);
export const builder = (yargsBuilder: typeof yargs) => yargsBuilder.command(network).command(neotracker);
55 changes: 55 additions & 0 deletions packages/neo-one-cli/src/cmd/start/neotracker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { cliLogger } from '@neo-one/logger';
import { Yarguments } from '@neo-one/utils-node';
import execa from 'execa';
import * as nodePath from 'path';
import yargs from 'yargs';
import { isRunning, start } from '../../common';
import { findKillProcess } from '../../utils';
import { writePidFile } from './writePidFile';

export const command = 'neotracker';
export const describe = 'Start a NEO tracker instance using the project configuration.';
export const builder = (yargsBuilder: typeof yargs) =>
yargsBuilder
.boolean('reset')
.describe('reset', 'Reset the NEO tracker database.')
.default('reset', false);
export const handler = (argv: Yarguments<ReturnType<typeof builder>>) => {
start(async (_cmd, config) => {
const running = await isRunning(config.neotracker.port);
if (running) {
if (argv.reset) {
await findKillProcess('neotracker', config);
} else {
cliLogger.info('NEO tracker is already running');

return undefined;
}
}

const args = [
'neotracker',
'--port',
`${config.neotracker.port}`,
'--nodeRpcUrl',
`http://localhost:${config.network.port}/rpc`,
'--dbFileName',
nodePath.resolve(config.neotracker.path, 'db.sqlite'),
];
const proc = execa(
nodePath.resolve(require.resolve('@neotracker/core/bin'), '../', 'neotracker'),
argv.reset ? args.concat(['--resetDB']) : args,
{
cleanup: false,
stdio: 'ignore',
},
);
proc.unref();

await writePidFile('neotracker', proc, config);

return async () => {
proc.kill();
};
});
};
50 changes: 3 additions & 47 deletions packages/neo-one-cli/src/cmd/start/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,9 @@ import { common, crypto } from '@neo-one/client-common';
import { cliLogger } from '@neo-one/logger';
import { FullNode } from '@neo-one/node';
import { createMain } from '@neo-one/node-neo-settings';
import * as fs from 'fs-extra';
import net from 'net';
import * as nodePath from 'path';
import yargs from 'yargs';
import { getNetworkProcessIDFile, getPrimaryKeys, start } from '../../common';

async function isRunning(port: number) {
let resolve: (running: boolean) => void;
let reject: (err: Error) => void;
// tslint:disable-next-line promise-must-complete
const promise = new Promise<boolean>((resolver, rejector) => {
resolve = resolver;
reject = rejector;
});

const cleanup = () => {
client.removeAllListeners('connect');
client.removeAllListeners('error');
client.end();
client.destroy();
client.unref();
};

const onConnect = () => {
resolve(true);
cleanup();
};

const onError = (error: Error) => {
// tslint:disable-next-line no-any
if ((error as any).code !== 'ECONNREFUSED') {
reject(error);
} else {
resolve(false);
}
cleanup();
};

const client = new net.Socket();
client.once('connect', onConnect);
client.once('error', onError);
client.connect({ port, host: '127.0.0.1' });

return promise;
}
import { getPrimaryKeys, isRunning, start } from '../../common';
import { writePidFile } from './writePidFile';

export const command = 'network';
export const describe = 'Start a NEO•ONE development network using the project configuration.';
Expand Down Expand Up @@ -88,9 +46,7 @@ export const handler = () => {

await fullNode.start();

const pidFile = getNetworkProcessIDFile(config);
await fs.ensureDir(nodePath.dirname(pidFile));
await fs.writeFile(pidFile, process.pid);
await writePidFile('network', process, config);

return async () => {
await fullNode.stop();
Expand Down
15 changes: 15 additions & 0 deletions packages/neo-one-cli/src/cmd/start/writePidFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Configuration } from '@neo-one/cli-common';
import { ExecaChildProcess } from 'execa';
import * as fs from 'fs-extra';
import * as nodePath from 'path';
import { getProcessIDFile } from '../../common';

export const writePidFile = async (
name: 'network' | 'neotracker',
proc: NodeJS.Process | ExecaChildProcess,
config: Configuration,
) => {
const pidFile = getProcessIDFile(config, name);
await fs.ensureDir(nodePath.dirname(pidFile));
await fs.writeFile(pidFile, proc.pid);
};
3 changes: 2 additions & 1 deletion packages/neo-one-cli/src/cmd/stop/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import yargs from 'yargs';
import * as neotracker from './neotracker';
import * as network from './network';

export const command = 'stop';
export const describe = 'Stop NEO•ONE services.';
export const builder = (yargsBuilder: typeof yargs) => yargsBuilder.command(network);
export const builder = (yargsBuilder: typeof yargs) => yargsBuilder.command(network).command(neotracker);
12 changes: 12 additions & 0 deletions packages/neo-one-cli/src/cmd/stop/neotracker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import yargs from 'yargs';
import { start } from '../../common';
import { findKillProcess } from '../../utils';

export const command = 'neotracker';
export const describe = 'Stops the local neotracker instance.';
export const builder = (yargsBuilder: typeof yargs) => yargsBuilder;
export const handler = () => {
start(async (_cmd, config) => {
await findKillProcess('neotracker', config);
});
};
Loading

0 comments on commit 9a3e32a

Please sign in to comment.