From a062ebce05f5cb8149402ba32c04fde1c10c9917 Mon Sep 17 00:00:00 2001 From: hamed musallam Date: Mon, 20 Nov 2023 16:17:31 +0100 Subject: [PATCH 1/3] feat: nmrium snapshot cli --- app/scripts/nmr-snapshot-cli/Dockerfile | 24 ++++ app/scripts/nmr-snapshot-cli/bin/index.js | 144 ++++++++++++++++++++++ app/scripts/nmr-snapshot-cli/package.json | 21 ++++ 3 files changed, 189 insertions(+) create mode 100644 app/scripts/nmr-snapshot-cli/Dockerfile create mode 100755 app/scripts/nmr-snapshot-cli/bin/index.js create mode 100644 app/scripts/nmr-snapshot-cli/package.json diff --git a/app/scripts/nmr-snapshot-cli/Dockerfile b/app/scripts/nmr-snapshot-cli/Dockerfile new file mode 100644 index 0000000..aef252e --- /dev/null +++ b/app/scripts/nmr-snapshot-cli/Dockerfile @@ -0,0 +1,24 @@ +# build the image ` docker build --tag nmr-snapshot-cli . ` +# run the container ` docker run -it nmr-snapshot-cli bash ` + +FROM mcr.microsoft.com/playwright:v1.40.0-jammy + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +WORKDIR /app + +#ENV BASE_NMRIUM_URL=https://nmrium.nmrxiv.org/ +ENV BASE_NMRIUM_URL=https://nmriumdev.nmrxiv.org/ + +COPY package.json ./ + +RUN npm i + +COPY . ./ + +#install the nmr-snapshot-cli as a global package +#example, nmr-snapshot-cli -u https://cheminfo.github.io/bruker-data-test/data/zipped/aspirin-1h.zip +RUN npm install . -g + + + diff --git a/app/scripts/nmr-snapshot-cli/bin/index.js b/app/scripts/nmr-snapshot-cli/bin/index.js new file mode 100755 index 0000000..275d8fa --- /dev/null +++ b/app/scripts/nmr-snapshot-cli/bin/index.js @@ -0,0 +1,144 @@ +#!/usr/bin/env node +const { join, isAbsolute } = require("path"); +const yargs = require("yargs"); +const loader = require("nmr-load-save"); +const fileUtils = require("filelist-utils"); +const playwright = require('playwright'); + +const usageMessage = "Usage: nmr-snapshot-cli -u or -p " + +const options = yargs + .usage(usageMessage) + .option("u", { alias: "url", describe: "File URL", type: "string", nargs: 1 }) + .option("p", { alias: "path", describe: "Directory path", type: "string", nargs: 1 }).showHelpOnFail(); + + +const PARSING_OPTIONS = { + onLoadProcessing: { autoProcessing: true }, + sourceSelector: { general: { dataSelection: 'preferFT' } }, +} + + +function generateNMRiumURL() { + const baseURL = process.env['BASE_NMRIUM_URL']; + const url = new URL(baseURL) + url.searchParams.append('workspace', "embedded") + return url.toString() +} + +async function getSpectraViewAsBase64(nmriumState) { + const { data: { spectra }, version } = nmriumState; + const browser = await playwright.chromium.launch() + const context = await browser.newContext(playwright.devices['Desktop Chrome HiDPI']) + const page = await context.newPage() + + const url = generateNMRiumURL() + + await page.goto(url) + + await page.locator('text=Loading').waitFor({ state: 'hidden' }); + + let snapshots = [] + + for (const spectrum of spectra || []) { + const spectrumObject = { + version, + data: { + spectra: [{ ...spectrum }], + } + + } + + // convert typed array to array + const stringObject = JSON.stringify(spectrumObject, (key, value) => { + return ArrayBuffer.isView(value) ? Array.from(value) : value + }) + + // load the spectrum into NMRium using the custom event + await page.evaluate( + ` + window.postMessage({ type: "nmr-wrapper:load", data:{data: ${stringObject},type:"nmrium"}}, '*'); + ` + ) + + //wait for NMRium process and load spectra + await page.locator('text=Loading').waitFor({ state: 'hidden' }); + + // take a snapshot for the spectrum + try { + const snapshot = await page.locator('#nmrSVG .container').screenshot() + + snapshots.push({ + image: snapshot.toString('base64'), + id: spectrum.id, + }) + } catch (e) { + console.log(e) + } + } + + await context.close() + await browser.close() + + return snapshots; +} + + +async function captureSpectrumSnapshotFromURL(url) { + const { pathname: relativePath, origin: baseURL } = new URL(url); + const source = { + entries: [ + { + relativePath, + } + ], + baseURL + }; + const fileCollection = await fileUtils.fileCollectionFromWebSource(source, {}); + + const { + nmriumState + } = await loader.read(fileCollection, PARSING_OPTIONS); + + + return getSpectraViewAsBase64(nmriumState); +} + + +async function captureSpectrumSnapshotFromFilePath(path) { + const dirPath = isAbsolute(path) ? path : join(process.cwd(), path) + + const fileCollection = await fileUtils.fileCollectionFromPath(dirPath, {}); + + const { + nmriumState + } = await loader.read(fileCollection, PARSING_OPTIONS); + return getSpectraViewAsBase64(nmriumState); +} + + +const parameters = options.argv; + +if (parameters.u && parameters.p) { + options.showHelp(); +} else { + + if (parameters.u) { + captureSpectrumSnapshotFromURL(parameters.u).then((result) => { + console.log(JSON.stringify(result)) + }) + + } + + if (parameters.p) { + captureSpectrumSnapshotFromFilePath(parameters.p).then((result) => { + console.log(JSON.stringify(result)) + }) + } + +} + + + + + diff --git a/app/scripts/nmr-snapshot-cli/package.json b/app/scripts/nmr-snapshot-cli/package.json new file mode 100644 index 0000000..7076e1c --- /dev/null +++ b/app/scripts/nmr-snapshot-cli/package.json @@ -0,0 +1,21 @@ +{ + "name": "test-node", + "version": "1.0.0", + "description": "", + "main": "bin/index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bin": { + "nmr-snapshot-cli": "./bin/index.js" + }, + "dependencies": { + "filelist-utils": "^1.10.2", + "nmr-load-save": "^0.23.3", + "playwright": "^1.40.0", + "yargs": "^17.7.2" + } +} \ No newline at end of file From a010f98d1dad058ff1d79a30d090a5827007e823 Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Wed, 22 Nov 2023 13:47:19 +0100 Subject: [PATCH 2/3] fix: add nmr-snapshot to docker-compose --- docker-compose.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index a36d7f0..544a02e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -37,6 +37,11 @@ services: entrypoint: /bin/sh stdin_open: true tty: true + nmr-snapshot: + build: ./app/scripts/nmr-snapshot-cli + entrypoint: /bin/sh + stdin_open: true + tty: true prometheus: image: prom/prometheus container_name: nmrkit_prometheus From 74f2c23ff395d171e43662337123c11ef289ca9b Mon Sep 17 00:00:00 2001 From: hamed musallam Date: Thu, 23 Nov 2023 19:11:23 +0100 Subject: [PATCH 3/3] refactor: combine the functionality of nmr-snapshot-cli with nmr-cli and remove nmr-snapshot-cli3 --- app/scripts/nmr-cli/Dockerfile | 10 +- app/scripts/nmr-cli/bin/index.js | 180 +++++++++++++++++----- app/scripts/nmr-cli/package-lock.json | 44 +++++- app/scripts/nmr-cli/package.json | 3 +- app/scripts/nmr-snapshot-cli/Dockerfile | 24 --- app/scripts/nmr-snapshot-cli/bin/index.js | 144 ----------------- app/scripts/nmr-snapshot-cli/package.json | 21 --- docker-compose.yml | 5 - 8 files changed, 191 insertions(+), 240 deletions(-) delete mode 100644 app/scripts/nmr-snapshot-cli/Dockerfile delete mode 100755 app/scripts/nmr-snapshot-cli/bin/index.js delete mode 100644 app/scripts/nmr-snapshot-cli/package.json diff --git a/app/scripts/nmr-cli/Dockerfile b/app/scripts/nmr-cli/Dockerfile index 7aaf2e9..a6b0393 100644 --- a/app/scripts/nmr-cli/Dockerfile +++ b/app/scripts/nmr-cli/Dockerfile @@ -1,15 +1,19 @@ # build the image ` docker build --tag nmr-cli . ` # run the container ` docker run -it nmr-cli bash ` -FROM node:20.9.0-alpine -# a temporary command to add bash to the Docker image to be able to run the container with an interactive Shell for testing purpose -RUN apk update && apk add bash +FROM mcr.microsoft.com/playwright:v1.40.0-jammy + SHELL ["/bin/bash", "-o", "pipefail", "-c"] WORKDIR /app +#ENV BASE_NMRIUM_URL=https://nmrium.nmrxiv.org/ +ENV BASE_NMRIUM_URL=https://nmriumdev.nmrxiv.org/ + + COPY package.json ./ COPY package-lock.json ./ + RUN npm install COPY . ./ diff --git a/app/scripts/nmr-cli/bin/index.js b/app/scripts/nmr-cli/bin/index.js index 7556d97..a8a895b 100755 --- a/app/scripts/nmr-cli/bin/index.js +++ b/app/scripts/nmr-cli/bin/index.js @@ -1,64 +1,162 @@ #!/usr/bin/env node -const {join,isAbsolute}= require("path"); +const { join, isAbsolute } = require("path"); const yargs = require("yargs"); const loader = require("nmr-load-save"); const fileUtils = require("filelist-utils"); +const playwright = require('playwright'); -const usageMessage ="Usage: nmr-cli -u or -p " +const usageMessage = "Usage: nmr-cli -u or -p -s" + + +/** + * How to Use the Command Line Tool: + * Example 1: Process spectra files from a URL + * Usage: nmr-cli -u https://example.com/file.zip + * ------------------------------------------------------------------------- + * Example 2: process a spectra files from a directory + * Usage: nmr-cli -p /path/to/directory + * ------------------------------------------------------------------------- + * you could also combine the above examples with an optional parameter to capturing a snapshot using the -s option + * + */ const options = yargs - .usage(usageMessage) - .option("u", { alias: "url", describe: "File URL", type: "string",nargs:1}) - .option("p", { alias: "path", describe: "Directory path", type: "string",nargs:1}).showHelpOnFail(); - - async function loadSpectrumFromURL(url) { - const {pathname:relativePath,origin:baseURL} = new URL(url); - const source = { - entries: [ - { - relativePath, - } - ], - baseURL - }; - const fileCollection = await fileUtils.fileCollectionFromWebSource(source,{}); - - const { - nmriumState: { data }, - } = await loader.read(fileCollection); - return data; + .usage(usageMessage) + .option("u", { alias: "url", describe: "File URL", type: "string", nargs: 1 }) + .option("p", { alias: "path", describe: "Directory path", type: "string", nargs: 1 }) + .option("s", { alias: "capture-snapshot", describe: "Capture snapshot", type: "boolean" }).showHelpOnFail(); + + + + +function generateNMRiumURL() { + const baseURL = process.env['BASE_NMRIUM_URL']; + const url = new URL(baseURL) + url.searchParams.append('workspace', "embedded") + return url.toString() +} + +async function captureSpectraViewAsBase64(nmriumState) { + const { data: { spectra }, version } = nmriumState; + const browser = await playwright.chromium.launch() + const context = await browser.newContext(playwright.devices['Desktop Chrome HiDPI']) + const page = await context.newPage() + + const url = generateNMRiumURL() + + await page.goto(url) + + await page.locator('text=Loading').waitFor({ state: 'hidden' }); + + let snapshots = [] + + for (const spectrum of spectra || []) { + const spectrumObject = { + version, + data: { + spectra: [{ ...spectrum }], + } + + } + + // convert typed array to array + const stringObject = JSON.stringify(spectrumObject, (key, value) => { + return ArrayBuffer.isView(value) ? Array.from(value) : value + }) + + // load the spectrum into NMRium using the custom event + await page.evaluate( + ` + window.postMessage({ type: "nmr-wrapper:load", data:{data: ${stringObject},type:"nmrium"}}, '*'); + ` + ) + + //wait for NMRium process and load spectra + await page.locator('text=Loading').waitFor({ state: 'hidden' }); + + // take a snapshot for the spectrum + try { + const snapshot = await page.locator('#nmrSVG .container').screenshot() + + snapshots.push({ + image: snapshot.toString('base64'), + id: spectrum.id, + }) + } catch (e) { + console.log(e) + } } + await context.close() + await browser.close() + + return snapshots; +} - async function loadSpectrumFromFilePath(path) { - const dirPath = isAbsolute(path)?path:join(process.cwd(),path) - - const fileCollection = await fileUtils.fileCollectionFromPath(dirPath,{}); - - const { - nmriumState: { data }, - } = await loader.read(fileCollection); - return data; +async function loadSpectrumFromURL(url, enableSnapshot = false) { + const { pathname: relativePath, origin: baseURL } = new URL(url); + const source = { + entries: [ + { + relativePath, + } + ], + baseURL + }; + const fileCollection = await fileUtils.fileCollectionFromWebSource(source, {}); + + const { + nmriumState: { data, version }, + } = await loader.read(fileCollection); + + let images = [] + + if (enableSnapshot) { + images = await captureSpectraViewAsBase64({ data, version }); } - const parameters = options.argv; + return { data, version, images }; +} + + +async function loadSpectrumFromFilePath(path, enableSnapshot = false) { + const dirPath = isAbsolute(path) ? path : join(process.cwd(), path) + + const fileCollection = await fileUtils.fileCollectionFromPath(dirPath, {}); + + const { + nmriumState: { data, version } + } = await loader.read(fileCollection); + + let images = [] -if(parameters.u && parameters.p){ + if (enableSnapshot) { + images = await captureSpectraViewAsBase64({ data, version }); + } + + + return { data, version, images }; +} + + +const parameters = options.argv; + +if (parameters.u && parameters.p) { options.showHelp(); -}else{ +} else { - if(parameters.u){ - loadSpectrumFromURL(parameters.u).then((result)=>{ - console.log(JSON.stringify(result)) - }) + if (parameters.u) { + loadSpectrumFromURL(parameters.u, parameters.s).then((result) => { + console.log(JSON.stringify(result)) + }) } - if(parameters.p){ - loadSpectrumFromFilePath(parameters.p).then((result)=>{ + if (parameters.p) { + loadSpectrumFromFilePath(parameters.p, parameters.s).then((result) => { console.log(JSON.stringify(result)) - }) + }) } } diff --git a/app/scripts/nmr-cli/package-lock.json b/app/scripts/nmr-cli/package-lock.json index fa7369b..2497fcf 100644 --- a/app/scripts/nmr-cli/package-lock.json +++ b/app/scripts/nmr-cli/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "filelist-utils": "^1.10.2", "nmr-load-save": "^0.23.11", + "playwright": "^1.40.1", "yargs": "^17.7.2" }, "bin": { @@ -256,6 +257,19 @@ "node": ">= 6" } }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -857,6 +871,34 @@ "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" }, + "node_modules/playwright": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.1.tgz", + "integrity": "sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==", + "dependencies": { + "playwright-core": "1.40.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.1.tgz", + "integrity": "sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -1036,4 +1078,4 @@ } } } -} +} \ No newline at end of file diff --git a/app/scripts/nmr-cli/package.json b/app/scripts/nmr-cli/package.json index 7250a89..83792f0 100644 --- a/app/scripts/nmr-cli/package.json +++ b/app/scripts/nmr-cli/package.json @@ -15,6 +15,7 @@ "dependencies": { "filelist-utils": "^1.10.2", "nmr-load-save": "^0.23.11", + "playwright": "^1.40.1", "yargs": "^17.7.2" } -} +} \ No newline at end of file diff --git a/app/scripts/nmr-snapshot-cli/Dockerfile b/app/scripts/nmr-snapshot-cli/Dockerfile deleted file mode 100644 index aef252e..0000000 --- a/app/scripts/nmr-snapshot-cli/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# build the image ` docker build --tag nmr-snapshot-cli . ` -# run the container ` docker run -it nmr-snapshot-cli bash ` - -FROM mcr.microsoft.com/playwright:v1.40.0-jammy - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] - -WORKDIR /app - -#ENV BASE_NMRIUM_URL=https://nmrium.nmrxiv.org/ -ENV BASE_NMRIUM_URL=https://nmriumdev.nmrxiv.org/ - -COPY package.json ./ - -RUN npm i - -COPY . ./ - -#install the nmr-snapshot-cli as a global package -#example, nmr-snapshot-cli -u https://cheminfo.github.io/bruker-data-test/data/zipped/aspirin-1h.zip -RUN npm install . -g - - - diff --git a/app/scripts/nmr-snapshot-cli/bin/index.js b/app/scripts/nmr-snapshot-cli/bin/index.js deleted file mode 100755 index 275d8fa..0000000 --- a/app/scripts/nmr-snapshot-cli/bin/index.js +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/env node -const { join, isAbsolute } = require("path"); -const yargs = require("yargs"); -const loader = require("nmr-load-save"); -const fileUtils = require("filelist-utils"); -const playwright = require('playwright'); - -const usageMessage = "Usage: nmr-snapshot-cli -u or -p " - -const options = yargs - .usage(usageMessage) - .option("u", { alias: "url", describe: "File URL", type: "string", nargs: 1 }) - .option("p", { alias: "path", describe: "Directory path", type: "string", nargs: 1 }).showHelpOnFail(); - - -const PARSING_OPTIONS = { - onLoadProcessing: { autoProcessing: true }, - sourceSelector: { general: { dataSelection: 'preferFT' } }, -} - - -function generateNMRiumURL() { - const baseURL = process.env['BASE_NMRIUM_URL']; - const url = new URL(baseURL) - url.searchParams.append('workspace', "embedded") - return url.toString() -} - -async function getSpectraViewAsBase64(nmriumState) { - const { data: { spectra }, version } = nmriumState; - const browser = await playwright.chromium.launch() - const context = await browser.newContext(playwright.devices['Desktop Chrome HiDPI']) - const page = await context.newPage() - - const url = generateNMRiumURL() - - await page.goto(url) - - await page.locator('text=Loading').waitFor({ state: 'hidden' }); - - let snapshots = [] - - for (const spectrum of spectra || []) { - const spectrumObject = { - version, - data: { - spectra: [{ ...spectrum }], - } - - } - - // convert typed array to array - const stringObject = JSON.stringify(spectrumObject, (key, value) => { - return ArrayBuffer.isView(value) ? Array.from(value) : value - }) - - // load the spectrum into NMRium using the custom event - await page.evaluate( - ` - window.postMessage({ type: "nmr-wrapper:load", data:{data: ${stringObject},type:"nmrium"}}, '*'); - ` - ) - - //wait for NMRium process and load spectra - await page.locator('text=Loading').waitFor({ state: 'hidden' }); - - // take a snapshot for the spectrum - try { - const snapshot = await page.locator('#nmrSVG .container').screenshot() - - snapshots.push({ - image: snapshot.toString('base64'), - id: spectrum.id, - }) - } catch (e) { - console.log(e) - } - } - - await context.close() - await browser.close() - - return snapshots; -} - - -async function captureSpectrumSnapshotFromURL(url) { - const { pathname: relativePath, origin: baseURL } = new URL(url); - const source = { - entries: [ - { - relativePath, - } - ], - baseURL - }; - const fileCollection = await fileUtils.fileCollectionFromWebSource(source, {}); - - const { - nmriumState - } = await loader.read(fileCollection, PARSING_OPTIONS); - - - return getSpectraViewAsBase64(nmriumState); -} - - -async function captureSpectrumSnapshotFromFilePath(path) { - const dirPath = isAbsolute(path) ? path : join(process.cwd(), path) - - const fileCollection = await fileUtils.fileCollectionFromPath(dirPath, {}); - - const { - nmriumState - } = await loader.read(fileCollection, PARSING_OPTIONS); - return getSpectraViewAsBase64(nmriumState); -} - - -const parameters = options.argv; - -if (parameters.u && parameters.p) { - options.showHelp(); -} else { - - if (parameters.u) { - captureSpectrumSnapshotFromURL(parameters.u).then((result) => { - console.log(JSON.stringify(result)) - }) - - } - - if (parameters.p) { - captureSpectrumSnapshotFromFilePath(parameters.p).then((result) => { - console.log(JSON.stringify(result)) - }) - } - -} - - - - - diff --git a/app/scripts/nmr-snapshot-cli/package.json b/app/scripts/nmr-snapshot-cli/package.json deleted file mode 100644 index 7076e1c..0000000 --- a/app/scripts/nmr-snapshot-cli/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "test-node", - "version": "1.0.0", - "description": "", - "main": "bin/index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": "", - "license": "ISC", - "bin": { - "nmr-snapshot-cli": "./bin/index.js" - }, - "dependencies": { - "filelist-utils": "^1.10.2", - "nmr-load-save": "^0.23.3", - "playwright": "^1.40.0", - "yargs": "^17.7.2" - } -} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 544a02e..a36d7f0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -37,11 +37,6 @@ services: entrypoint: /bin/sh stdin_open: true tty: true - nmr-snapshot: - build: ./app/scripts/nmr-snapshot-cli - entrypoint: /bin/sh - stdin_open: true - tty: true prometheus: image: prom/prometheus container_name: nmrkit_prometheus