Skip to content

Commit

Permalink
Merge pull request #15 from fabianbormann/develop
Browse files Browse the repository at this point in the history
feat: add option to stop the node once it's running
  • Loading branch information
fabianbormann authored May 18, 2023
2 parents 7cac947 + 4d53d22 commit b5e2cb7
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 25 deletions.
123 changes: 110 additions & 13 deletions public/electron.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ const spawn = require('child_process').spawn;
const fs = require('fs/promises');
const ip = require('ip');

let nodeInstance = null;
let intervalId = -1;
let nodeRunning = false;

class NodeAlreadyRunningError extends Error {}

const networks = {
mainnet: {
protocolMagic: 764824073,
Expand Down Expand Up @@ -96,6 +102,10 @@ const unpackArchive = (directory) =>

const startNode = (directory, network) =>
new Promise((resolve, reject) => {
if (nodeInstance !== null) {
throw new NodeAlreadyRunningError();
}

const nodeBinary = nodeBinaries[process.platform];
const configDirectory = path.join(directory, `${network}-config`);
const databaseDirectory = path.join(directory, `${network}-db`);
Expand All @@ -104,7 +114,7 @@ const startNode = (directory, network) =>
nodeBinary.replace('.tar.gz', '').replace('.zip', '')
);

const child = spawn(path.join(binaryPath, 'cardano-node'), [
nodeInstance = spawn(path.join(binaryPath, 'cardano-node'), [
'run',
'--topology',
path.join(configDirectory, 'topology.json'),
Expand All @@ -119,20 +129,20 @@ const startNode = (directory, network) =>
'--config',
path.join(configDirectory, 'config.json'),
]);
child.on('close', (code) => {
console.log(`child process exited with code ${code}`);
if (code === 0) {
resolve();
} else {
reject();
}

nodeInstance.on('error', (error) => {
console.log(`child process exited with error ${error.name}`);
console.log(error.message);
reject();
});

child.stdout.on('data', (data) => {
nodeInstance.on('spawn', () => resolve());

nodeInstance.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});

child.stderr.on('data', (data) => {
nodeInstance.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
});
Expand Down Expand Up @@ -197,8 +207,6 @@ function createWindow() {
return mainWindow;
}

let intervalId = -1;

app.whenReady().then(() => {
const mainWindow = createWindow();

Expand Down Expand Up @@ -231,7 +239,21 @@ app.whenReady().then(() => {
}
});

ipcMain.on('stop-node', () => {
if (nodeRunning) {
nodeRunning = false;
mainWindow.webContents.send('node-status', {
id: -1,
timestamp: new Date().getTime(),
status: 'shutdown',
message: 'stopping the node ⏸ #{...}',
});
}
});

ipcMain.on('start-node', async (_event, directory, network = 'mainnet') => {
nodeRunning = true;

mainWindow.webContents.send('node-status', {
id: 0,
timestamp: new Date().getTime(),
Expand Down Expand Up @@ -261,6 +283,17 @@ app.whenReady().then(() => {
return;
}

if (!nodeRunning) {
mainWindow.webContents.send('node-status', {
id: -1,
timestamp: new Date().getTime(),
status: 'idle',
message: 'the node has been successfully stopped ✅!',
});

return;
}

mainWindow.webContents.send('node-status', {
id: 0,
timestamp: new Date().getTime(),
Expand All @@ -275,6 +308,15 @@ app.whenReady().then(() => {
message: 'download configuration and node topology #{...}',
});
await downloadConfig(directory, network);
if (!nodeRunning) {
mainWindow.webContents.send('node-status', {
id: -1,
timestamp: new Date().getTime(),
status: 'idle',
message: 'the node has been successfully stopped ✅!',
});
return;
}
mainWindow.webContents.send('node-status', {
id: 1,
timestamp: new Date().getTime(),
Expand Down Expand Up @@ -310,14 +352,68 @@ app.whenReady().then(() => {
message: 'node initialization running #{...}',
});

startNode(directory, network);
try {
await startNode(directory, network);
} catch (error) {
if (error instanceof NodeAlreadyRunningError) {
mainWindow.webContents.send('node-status', {
id: 2,
timestamp: new Date().getTime(),
status: 'running',
message: 'node already running',
});
} else {
mainWindow.webContents.send('node-status', {
id: 2,
timestamp: new Date().getTime(),
status: 'error',
message: `failed to start node${
typeof error.message !== 'undefined' && ': ' + error.message
}`,
});
}
return;
}

if (nodeRunning) {
mainWindow.webContents.send('node-status', {
id: 2,
timestamp: new Date().getTime(),
status: 'running',
message: 'the node is up and running 🚀!',
});
} else {
nodeInstance.kill('SIGINT');
nodeInstance = null;
mainWindow.webContents.send('node-status', {
id: -1,
timestamp: new Date().getTime(),
status: 'idle',
message: 'the node has been successfully stopped ✅!',
});
return;
}

const nodeBinary = nodeBinaries[process.platform];
const binaryPath = path.join(
directory,
nodeBinary.replace('.tar.gz', '').replace('.zip', '')
);

const getCurrentTip = () => {
if (!nodeRunning) {
mainWindow.webContents.send('node-status', {
id: -1,
timestamp: new Date().getTime(),
status: 'idle',
message: 'the node has been successfully stopped ✅!',
});
nodeInstance.kill('SIGINT');
nodeInstance = null;
clearInterval(intervalId);
intervalId = -1;
return;
}
const databaseDirectory = path.join(directory, `${network}-db`);
const args = ['query', 'tip'];

Expand Down Expand Up @@ -349,6 +445,7 @@ app.whenReady().then(() => {
}
}
});

child.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
Expand Down
1 change: 1 addition & 0 deletions public/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ contextBridge.exposeInMainWorld('electron', {
getDefaultDirectory: () => ipcRenderer.invoke('getDefaultPath'),
startNode: (directory, network) =>
ipcRenderer.send('start-node', directory, network),
stopNode: () => ipcRenderer.send('stop-node'),
});
2 changes: 1 addition & 1 deletion src/global/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export type MessageType = 'success' | 'error' | 'warning' | 'info';

export type NodeStatus = 'idle' | 'download' | 'running' | 'error';
export type NodeStatus = 'idle' | 'download' | 'running' | 'error' | 'shutdown';
export type IpcEventListener = (
channel: string,
callback: (argument: any) => void
Expand Down
64 changes: 53 additions & 11 deletions src/pages/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,19 @@ const Dashboard = () => {

const startNode = (window as any).electron?.startNode;
if (typeof startNode === 'function') {
startNode(directory, selectedNetwork);
setNodeRunning(true);
setNodeLog([
{ status: 'idle', message: 'cardano-node-ui:~$', id: -1, timestamp: 0 },
]);
startNode(directory, selectedNetwork);
}
};

const stopNode = () => {
const stopNode = (window as any).electron?.stopNode;
if (typeof stopNode === 'function') {
stopNode();
setNodeRunning(false);
}
};

Expand All @@ -125,7 +136,7 @@ const Dashboard = () => {
);
formattedMessage = formattedMessage.replaceAll('#{:x:}', '❌');

if (ids.includes(line.id)) {
if (ids.includes(line.id) && line.id !== -1) {
const timestamp = Object.keys(messages).find(
(key) => messages[key as unknown as number].id === line.id
) as unknown as number;
Expand Down Expand Up @@ -198,6 +209,45 @@ const Dashboard = () => {
setSnackbarOpen(true);
};

const getActionButton = () => {
if (nodeStatus === 'idle' || nodeStatus === 'error') {
return (
<Button
sx={{ ml: 1, p: 2.5 }}
variant="contained"
color="secondary"
disableElevation
onClick={invokeStartNode}
>
Start
</Button>
);
} else if (nodeStatus === 'shutdown') {
return (
<Button
sx={{ ml: 1, p: 2.5, background: '#767676 !important' }}
variant="contained"
disableElevation
disabled
>
Stop
</Button>
);
} else {
return (
<Button
sx={{ ml: 1, p: 2.5 }}
variant="contained"
color="warning"
disableElevation
onClick={stopNode}
>
Stop
</Button>
);
}
};

return (
<Grid
container
Expand Down Expand Up @@ -278,15 +328,7 @@ const Dashboard = () => {
Preview
</MenuItem>
</Select>
<Button
sx={{ ml: 1, p: 2.5 }}
variant="contained"
color="secondary"
disableElevation
onClick={invokeStartNode}
>
Start
</Button>
{getActionButton()}
</Grid>
</Grid>

Expand Down

0 comments on commit b5e2cb7

Please sign in to comment.