diff --git a/package.json b/package.json index 2fc94b24..132852c1 100644 --- a/package.json +++ b/package.json @@ -1,3 +1,5 @@ + + { "name": "solana-workbench", "productName": "SolanaWorkbench", @@ -286,4 +288,4 @@ "pre-commit": "lint-staged" } } -} \ No newline at end of file +} diff --git a/src/main/ipc/docker.ts b/src/main/ipc/docker.ts index e1e98445..7f3f05b4 100644 --- a/src/main/ipc/docker.ts +++ b/src/main/ipc/docker.ts @@ -160,6 +160,49 @@ async function createContainer(image: string) { .catch(logger.error); } +export const stopValidatorContainer = () => { + const dockerClient = new Dockerode(); + const container = dockerClient.getContainer('solana-test-validator'); + logger.error(`request stop amman exec: solana-test-validator`); + log(`request stop amman exec: solana-test-validator`); + + return container + .exec({ + Cmd: ['/bin/bash', '-c', 'source /root/.bashrc && amman stop'], + AttachStdin: false, + AttachStdout: false, + }) + .then((e: Dockerode.Exec) => { + log('exec stop amman created'); + + return e.start({ + hijack: true, + stdin: false, + Detach: true, + Tty: true, + }); + }) + .then(() => { + logger.info('exec stop amman started '); + log('exec stop amman started '); + // TODO: wait til the validator has stopped.. + return 'OK'; + }); +}; + +export const removeValidatorContainer = () => { + const dockerClient = new Dockerode(); + const container = dockerClient.getContainer('solana-test-validator'); + logger.error(`remove requested: solana-test-validator`); + log(`remove requested: solana-test-validator`); + + return container.remove({ force: true }).then(() => { + logger.info('container removed '); + log('container removed '); + return 'OK'; + }); +}; + async function execAmman() { // TODO: this presupposes that this workbench session starts the validator // should change this so the `amman start` tee's to a file, and then use `docker exec tail -n 20` or something @@ -339,16 +382,7 @@ export function initDockerPromises() { `main: called DOCKER-RemoveValidatorContainer, ${image}, ${event}` ); - const dockerClient = new Dockerode(); - const container = dockerClient.getContainer('solana-test-validator'); - logger.error(`remove requested: solana-test-validator`); - log(`remove requested: solana-test-validator`); - - return container.remove({ force: true }).then(() => { - logger.info('container removed '); - log('container removed '); - return 'OK'; - }); + return removeValidatorContainer(); } ); @@ -367,35 +401,14 @@ export function initDockerPromises() { (image: unknown, event?: IpcEvent | undefined) => { logger.info(`main: called DOCKER-StopAmmanValidator, ${image}, ${event}`); - const dockerClient = new Dockerode(); - const container = dockerClient.getContainer('solana-test-validator'); - logger.error(`request stop amman exec: solana-test-validator`); - log(`request stop amman exec: solana-test-validator`); - - return container - .exec({ - Cmd: ['/bin/bash', '-c', 'source /root/.bashrc && amman stop'], - AttachStdin: false, - AttachStdout: false, - }) - .then((e: Dockerode.Exec) => { - log('exec stop amman created'); - - return e.start({ - hijack: true, - stdin: false, - Detach: true, - Tty: true, - }); - }) - .then(() => { - logger.info('exec stop amman started '); - log('exec stop amman started '); - // TODO: wait til the validator has stopped.. - return 'OK'; - }); + return stopValidatorContainer(); } ); } +export const inspectValidatorContainer = () => { + const dockerClient = new Dockerode(); + return dockerClient.getContainer('solana-test-validator').inspect(); +}; + export default {}; diff --git a/src/main/main.ts b/src/main/main.ts index 11eac62b..c4517168 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -1,4 +1,4 @@ -import { app, BrowserWindow, ipcMain, shell } from 'electron'; +import { app, BrowserWindow, ipcMain, shell, dialog } from 'electron'; import log from 'electron-log'; import { autoUpdater } from 'electron-updater'; import path from 'path'; @@ -7,7 +7,12 @@ import fetchAnchorIdl from './anchor'; import { RESOURCES_PATH } from './const'; import { initAccountPromises } from './ipc/accounts'; import { initConfigPromises } from './ipc/config'; -import { initDockerPromises } from './ipc/docker'; +import { + initDockerPromises, + inspectValidatorContainer, + stopValidatorContainer, + removeValidatorContainer, +} from './ipc/docker'; import { initLogging, logger } from './logger'; import MenuBuilder from './menu'; import { @@ -136,6 +141,50 @@ const createWindow = async () => { } }); + // eslint-disable-next-line consistent-return + mainWindow.on('close', async function (e: Event) { + e.preventDefault(); + + try { + const containerInspect = await inspectValidatorContainer(); + if (!containerInspect?.State?.Running) return app.exit(0); + } catch (err) { + logger.error(err); + app.exit(); // not doing show will make the window "un-closable" if an error occurs while inspecting + } + + const choice = dialog.showMessageBoxSync(mainWindow as BrowserWindow, { + type: 'question', + buttons: ['Stop', 'Stop & Remove', 'Leave Running', 'Cancel'], + title: 'Just before you leave', + message: + 'What would you like to do to the Solana Validator container before exiting?', + icon: getAssetPath('icon.png'), + }); + switch (choice) { + // Stop + case 0: + await stopValidatorContainer(); + app.exit(0); + break; + // Stop & Delete + case 1: + await stopValidatorContainer(); + await removeValidatorContainer(); + app.exit(0); + break; + // Leave Running + case 2: + // TODO might close multiple window at once. + app.exit(0); + break; + // Cancel + case 3: + break; + default: + } + }); + mainWindow.on('closed', () => { mainWindow = null; }); diff --git a/src/main/preload.js b/src/main/preload.js index 09e491e5..ec6c8071 100644 --- a/src/main/preload.js +++ b/src/main/preload.js @@ -26,6 +26,9 @@ contextBridge.exposeInMainWorld('electron', { fetchAnchorIDL(msg) { send('fetch-anchor-idl', msg); }, + closeWindowAction(option) { + send('close-window-actions', option); + }, on(method, func) { ipcRenderer.on(method, (event, ...args) => func(...args)); }, diff --git a/src/renderer/nav/Validator.tsx b/src/renderer/nav/Validator.tsx index 42ec2267..3e116f6f 100644 --- a/src/renderer/nav/Validator.tsx +++ b/src/renderer/nav/Validator.tsx @@ -226,7 +226,6 @@ const Validator = () => { .catch(logger.error); } else { logger.info('START AMMAN'); - // TODO: StartAmmanValidator blocks, no toast for now window.promiseIpc .send(`DOCKER-StartAmmanValidator`) diff --git a/src/renderer/vite.config.ts b/src/renderer/vite.config.ts index f0f7d874..270b0287 100644 --- a/src/renderer/vite.config.ts +++ b/src/renderer/vite.config.ts @@ -36,6 +36,7 @@ export default defineConfig({ buffer: true, }), ], + target: 'es2021', }, }, plugins: [ @@ -91,5 +92,6 @@ export default defineConfig({ assetsDir: '.', emptyOutDir: true, brotliSize: false, + target: 'es2021', }, });