diff --git a/.gitignore b/.gitignore index 0215abd..869f36b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,7 @@ cvmts/attic # Guac-rs guac-rs/target guac-rs/index.node + +# jpegturbo-rs +jpegturbo-rs/target +jpegturbo-rs/index.node diff --git a/.gitmodules b/.gitmodules index 76ac5b5..24e582d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "nodejs-rfb"] path = nodejs-rfb url = https://github.com/computernewb/nodejs-rfb -[submodule "jpeg-turbo"] - path = jpeg-turbo - url = https://github.com/computernewb/jpeg-turbo diff --git a/cvmts/package.json b/cvmts/package.json index fbf2c87..94754d5 100644 --- a/cvmts/package.json +++ b/cvmts/package.json @@ -11,12 +11,11 @@ "author": "Elijah R, modeco80", "license": "GPL-3.0", "dependencies": { - "@computernewb/jpeg-turbo": "*", "@cvmts/guac-rs": "*", + "@cvmts/jpegturbo-rs": "*", "@cvmts/qemu": "*", "execa": "^8.0.1", "mnemonist": "^0.39.5", - "piscina": "^4.4.0", "sharp": "^0.33.3", "toml": "^3.0.0", "ws": "^8.14.1" diff --git a/cvmts/src/CollabVMServer.ts b/cvmts/src/CollabVMServer.ts index fc5f7d3..5cb6f9b 100644 --- a/cvmts/src/CollabVMServer.ts +++ b/cvmts/src/CollabVMServer.ts @@ -810,7 +810,7 @@ export default class CollabVMServer { let display = this.VM.GetDisplay(); let displaySize = display.Size(); - let encoded = await JPEGEncoder.EncodeJpeg(display.Buffer(), displaySize, rect); + let encoded = await JPEGEncoder.Encode(display.Buffer(), displaySize, rect); return encoded.toString('base64'); } diff --git a/cvmts/src/JPEGEncoder.ts b/cvmts/src/JPEGEncoder.ts index 2cc3a6c..7e73243 100644 --- a/cvmts/src/JPEGEncoder.ts +++ b/cvmts/src/JPEGEncoder.ts @@ -1,59 +1,52 @@ -import path from 'node:path'; -import Piscina from 'piscina'; - import { Size, Rect } from '@cvmts/shared'; - -const kMaxJpegThreads = 4; -const kIdleTimeout = 25000; - -// Thread pool for doing JPEG encoding for rects. -const TheJpegEncoderPool = new Piscina({ - filename: path.join(import.meta.dirname + '/JPEGEncoderWorker.js'), - idleTimeout: kIdleTimeout, - maxThreads: kMaxJpegThreads -}); - -const TheThumbnailEncoderPool = new Piscina({ - filename: path.join(import.meta.dirname + '/ThumbnailJPEGEncoderWorker.js'), - idleTimeout: kIdleTimeout, - maxThreads: kMaxJpegThreads -}); +import sharp from 'sharp'; +import * as jpeg from '@cvmts/jpegturbo-rs'; // A good balance. TODO: Configurable? let gJpegQuality = 35; -export class JPEGEncoder { +const kThumbnailSize: Size = { + width: 400, + height: 300 +}; +// this returns appropiate Sharp options to deal with CVMTS raw framebuffers +// (which are RGBA bitmaps, essentially. We probably should abstract that out but +// that'd mean having to introduce that to rfb and oihwekjtgferklds;./tghnredsltg;erhds) +function GetRawSharpOptions(size: Size): sharp.CreateRaw { + return { + width: size.width, + height: size.height, + channels: 4 + }; +} + +export class JPEGEncoder { static SetQuality(quality: number) { gJpegQuality = quality; } - static async EncodeJpeg(canvas: Buffer, displaySize: Size, rect: Rect): Promise { + static async Encode(canvas: Buffer, displaySize: Size, rect: Rect): Promise { let offset = (rect.y * displaySize.width + rect.x) * 4; - - let res = await TheJpegEncoderPool.run({ - buffer: canvas.subarray(offset), + return jpeg.jpegEncode({ width: rect.width, height: rect.height, stride: displaySize.width, - quality: gJpegQuality + buffer: canvas.subarray(offset) }); - - // TODO: There's probably (definitely) a better way to fix this - if (res == undefined) return Buffer.from([]); - - // have to manually turn it back into a buffer because - // Piscina for some reason turns it into a Uint8Array - return Buffer.from(res); } - static async EncodeThumbnail(buffer: Buffer, size: Size) : Promise { - let res = await TheThumbnailEncoderPool.run({ - buffer: buffer, - size: size, - quality: gJpegQuality - }); + static async EncodeThumbnail(buffer: Buffer, size: Size): Promise { + let { data, info } = await sharp(buffer, { raw: GetRawSharpOptions(size) }) + .resize(kThumbnailSize.width, kThumbnailSize.height, { fit: 'fill' }) + .raw() + .toBuffer({ resolveWithObject: true }); - return Buffer.from(res) + return jpeg.jpegEncode({ + width: kThumbnailSize.width, + height: kThumbnailSize.height, + stride: kThumbnailSize.width, + buffer: data + }); } } diff --git a/cvmts/src/JPEGEncoderWorker.ts b/cvmts/src/JPEGEncoderWorker.ts deleted file mode 100644 index 124914b..0000000 --- a/cvmts/src/JPEGEncoderWorker.ts +++ /dev/null @@ -1,19 +0,0 @@ -import jpegTurbo from '@computernewb/jpeg-turbo'; -import Piscina from 'piscina'; - -export default async (opts: any) => { - try { - let res = await jpegTurbo.compress(opts.buffer, { - format: jpegTurbo.FORMAT_RGBA, - width: opts.width, - height: opts.height, - subsampling: jpegTurbo.SAMP_422, - stride: opts.stride, - quality: opts.quality || 75 - }); - - return Piscina.move(res); - } catch { - return; - } -}; diff --git a/cvmts/src/ThumbnailJPEGEncoderWorker.ts b/cvmts/src/ThumbnailJPEGEncoderWorker.ts deleted file mode 100644 index b957188..0000000 --- a/cvmts/src/ThumbnailJPEGEncoderWorker.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Size } from '@cvmts/shared'; -import Piscina from 'piscina'; -import sharp from 'sharp'; - -const kThumbnailSize: Size = { - width: 400, - height: 300 -}; - -// this returns appropiate Sharp options to deal with CVMTS raw framebuffers -// (which are RGBA bitmaps, essentially. We probably should abstract that out but -// that'd mean having to introduce that to rfb and oihwekjtgferklds;./tghnredsltg;erhds) -function GetRawSharpOptions(size: Size): sharp.CreateRaw { - return { - width: size.width, - height: size.height, - channels: 4 - }; -} - -export default async (opts: any) => { - try { - let out = await sharp(opts.buffer, { raw: GetRawSharpOptions(opts.size) }) - .resize(kThumbnailSize.width, kThumbnailSize.height, { fit: 'fill' }) - .jpeg({ - quality: opts.quality || 75 - }) - .toFormat('jpeg') - .toBuffer(); - - return out; - } catch { - return; - } - -}; diff --git a/jpeg-turbo b/jpeg-turbo deleted file mode 160000 index 6718ec1..0000000 --- a/jpeg-turbo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6718ec1fc12aeccdb1b1490a7a258f24e8f83164 diff --git a/jpegturbo-rs/Cargo.lock b/jpegturbo-rs/Cargo.lock new file mode 100644 index 0000000..60574c6 --- /dev/null +++ b/jpegturbo-rs/Cargo.lock @@ -0,0 +1,350 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "cc" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "jpegturbo-rs" +version = "0.1.0" +dependencies = [ + "neon", + "once_cell", + "tokio", + "turbojpeg-sys", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "neon" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d75440242411c87dc39847b0e33e961ec1f10326a9d8ecf9c1ea64a3b3c13dc" +dependencies = [ + "getrandom", + "libloading", + "neon-macros", + "once_cell", + "semver", + "send_wrapper", + "smallvec", +] + +[[package]] +name = "neon-macros" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6813fde79b646e47e7ad75f480aa80ef76a5d9599e2717407961531169ee38b" +dependencies = [ + "quote", + "syn", + "syn-mid", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-mid" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5dc35bb08dd1ca3dfb09dce91fd2d13294d6711c88897d9a9d60acf39bce049" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio" +version = "1.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +dependencies = [ + "backtrace", + "num_cpus", + "pin-project-lite", +] + +[[package]] +name = "turbojpeg-sys" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fa6daade3b979fb7454cce5ebcb9772ce7a1cf476ea27ed20ed06e13d9bc983" +dependencies = [ + "anyhow", + "cmake", + "libc", + "pkg-config", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/jpegturbo-rs/Cargo.toml b/jpegturbo-rs/Cargo.toml new file mode 100644 index 0000000..5fc50ae --- /dev/null +++ b/jpegturbo-rs/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "jpegturbo-rs" +description = "Rust powered JPEGTurbo sex" +version = "0.1.0" +edition = "2021" +exclude = ["index.node"] + +[lib] +crate-type = ["cdylib"] + +[dependencies] +neon = "1" +once_cell = "1.19.0" +tokio = { version = "1.38.0", features = [ "rt", "rt-multi-thread" ] } +turbojpeg-sys = "1.0.0" diff --git a/jpegturbo-rs/index.d.ts b/jpegturbo-rs/index.d.ts new file mode 100644 index 0000000..9c653e8 --- /dev/null +++ b/jpegturbo-rs/index.d.ts @@ -0,0 +1,15 @@ + +interface JpegInputArgs { + width: number, + height: number, + stride: number, // The width of your input framebuffer OR your image width (if encoding a full image) + buffer: Buffer + + // TODO: Allow different formats, or export a boxed ffi object which can store a format + // (i.e: new JpegEncoder(FORMAT_xxx)). +} + +/// Performs JPEG encoding. +export function jpegEncode(input: JpegInputArgs) : Promise; + +// TODO: Version that can downscale? diff --git a/jpegturbo-rs/index.js b/jpegturbo-rs/index.js new file mode 100644 index 0000000..5519fa2 --- /dev/null +++ b/jpegturbo-rs/index.js @@ -0,0 +1,6 @@ +// *sigh* +import { createRequire } from 'module'; +const require = createRequire(import.meta.url); + +export let {jpegEncode} = require('./index.node'); + diff --git a/jpegturbo-rs/package.json b/jpegturbo-rs/package.json new file mode 100644 index 0000000..58be5d6 --- /dev/null +++ b/jpegturbo-rs/package.json @@ -0,0 +1,16 @@ +{ + "name": "@cvmts/jpegturbo-rs", + "version": "0.1.0", + "packageManager": "yarn@4.1.1", + "type": "module", + "main": "index.js", + "types": "index.d.ts", + "scripts": { + "build": "cargo-cp-artifact -nc index.node -- cargo build --release --message-format=json-render-diagnostics", + "install": "yarn build", + "test": "cargo test" + }, + "devDependencies": { + "cargo-cp-artifact": "^0.1" + } +} diff --git a/jpegturbo-rs/src/jpeg_compressor.rs b/jpegturbo-rs/src/jpeg_compressor.rs new file mode 100644 index 0000000..56248c4 --- /dev/null +++ b/jpegturbo-rs/src/jpeg_compressor.rs @@ -0,0 +1,82 @@ +use turbojpeg_sys::*; + +pub struct Image<'a> { + pub buffer: &'a [u8], + pub width: u32, + pub height: u32, + pub stride: u32, + pub format: TJPF, +} + +pub struct JpegCompressor { + handle: tjhandle, + subsamp: TJSAMP, + quality: u32, +} + +unsafe impl Send for JpegCompressor {} + +impl JpegCompressor { + pub fn new() -> Self { + unsafe { + let init = Self { + handle: tjInitCompress(), + subsamp: TJSAMP_TJSAMP_422, + quality: 95, + }; + return init; + } + } + + pub fn set_quality(&mut self, quality: u32) { + self.quality = quality; + } + + pub fn set_subsamp(&mut self, samp: TJSAMP) { + self.subsamp = samp; + } + + pub fn compress_buffer<'a>(&self, image: &Image<'a>) -> Vec { + unsafe { + let size: usize = + tjBufSize(image.width as i32, image.height as i32, self.subsamp) as usize; + let mut vec = Vec::with_capacity(size); + + vec.resize(size, 0); + + let mut ptr: *mut u8 = vec.as_mut_ptr(); + let mut size: u64 = 0; + + let res = tjCompress2( + self.handle, + image.buffer.as_ptr(), + image.width as i32, + image.stride as i32, + image.height as i32, + image.format, + std::ptr::addr_of_mut!(ptr), + std::ptr::addr_of_mut!(size), + self.subsamp, + self.quality as i32, + (TJFLAG_NOREALLOC) as i32, + ); + + // TODO: Result sex so we can actually notify failure + if res == -1 { + return Vec::new(); + } + + // Truncate down to the size we're given back + vec.truncate(size as usize); + return vec; + } + } +} + +impl Drop for JpegCompressor { + fn drop(&mut self) { + unsafe { + tjDestroy(self.handle); + } + } +} diff --git a/jpegturbo-rs/src/lib.rs b/jpegturbo-rs/src/lib.rs new file mode 100644 index 0000000..dc3f498 --- /dev/null +++ b/jpegturbo-rs/src/lib.rs @@ -0,0 +1,91 @@ +use std::sync::{Arc, Mutex}; + +use neon::prelude::*; +use neon::types::buffer::TypedArray; + +use once_cell::sync::OnceCell; +use tokio::runtime::Runtime; + +use std::cell::RefCell; + +mod jpeg_compressor; + +fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> { + static RUNTIME: OnceCell = OnceCell::new(); + + RUNTIME + .get_or_try_init(Runtime::new) + .or_else(|err| cx.throw_error(&err.to_string())) +} + +thread_local! { + static COMPRESSOR: RefCell = RefCell::new(jpeg_compressor::JpegCompressor::new()); +} + +fn jpeg_encode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsPromise> { + let input = cx.argument::(0)?; + + // Get our input arguments here + let width: u64 = input.get::(cx, "width")?.value(cx) as u64; + let height: u64 = input.get::(cx, "height")?.value(cx) as u64; + let stride: u64 = input.get::(cx, "stride")?.value(cx) as u64; + let buffer: Handle = input.get(cx, "buffer")?; + + let (deferred, promise) = cx.promise(); + let channel = cx.channel(); + let runtime = runtime(cx)?; + + let buf = buffer.as_slice(cx); + + let copy: Arc>> = Arc::new(Mutex::new(Vec::with_capacity(buf.len()))); + + // Copy from the node buffer to our temporary buffer + { + let mut locked = copy.lock().unwrap(); + let cap = locked.capacity(); + locked.resize(cap, 0); + locked.copy_from_slice(buf); + } + + // Spawn off a tokio blocking pool thread that will do the work for us + runtime.spawn_blocking(move || { + let clone = Arc::clone(©); + let locked = clone.lock().unwrap(); + + let image: jpeg_compressor::Image = jpeg_compressor::Image { + buffer: locked.as_slice(), + width: width as u32, + height: height as u32, + + stride: (stride * 4u64) as u32, // I think? + format: turbojpeg_sys::TJPF_TJPF_RGBA, + }; + + let vec = COMPRESSOR.with(|lazy| { + let mut b = lazy.borrow_mut(); + b.set_quality(35); + b.set_subsamp(turbojpeg_sys::TJSAMP_TJSAMP_420); + b.compress_buffer(&image) + }); + + // Fulfill the Javascript promise with our encoded buffer + deferred.settle_with(&channel, move |mut cx| { + let mut buf = cx.buffer(vec.len())?; + let slice = buf.as_mut_slice(&mut cx); + slice.copy_from_slice(vec.as_slice()); + Ok(buf) + }); + }); + + Ok(promise) +} + +fn jpeg_encode(mut cx: FunctionContext) -> JsResult { + jpeg_encode_impl(&mut cx) +} + +#[neon::main] +fn main(mut cx: ModuleContext) -> NeonResult<()> { + cx.export_function("jpegEncode", jpeg_encode)?; + Ok(()) +} diff --git a/package.json b/package.json index 7c9552a..82387f8 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "workspaces": [ "shared", "guac-rs", - "jpeg-turbo", + "jpegturbo-rs", "nodejs-rfb", "qemu", "cvmts" diff --git a/yarn.lock b/yarn.lock index 72e6c52..2c8b671 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34,15 +34,6 @@ __metadata: languageName: node linkType: hard -"@computernewb/jpeg-turbo@npm:*, @computernewb/jpeg-turbo@workspace:jpeg-turbo": - version: 0.0.0-use.local - resolution: "@computernewb/jpeg-turbo@workspace:jpeg-turbo" - dependencies: - cmake-js: "npm:^7.2.0" - node-addon-api: "npm:^6.0.0" - languageName: unknown - linkType: soft - "@computernewb/nodejs-rfb@npm:*, @computernewb/nodejs-rfb@workspace:nodejs-rfb": version: 0.0.0-use.local resolution: "@computernewb/nodejs-rfb@workspace:nodejs-rfb" @@ -60,14 +51,13 @@ __metadata: version: 0.0.0-use.local resolution: "@cvmts/cvmts@workspace:cvmts" dependencies: - "@computernewb/jpeg-turbo": "npm:*" "@cvmts/guac-rs": "npm:*" + "@cvmts/jpegturbo-rs": "npm:*" "@cvmts/qemu": "npm:*" "@types/node": "npm:^20.12.5" "@types/ws": "npm:^8.5.5" execa: "npm:^8.0.1" mnemonist: "npm:^0.39.5" - piscina: "npm:^4.4.0" prettier: "npm:^3.2.5" sharp: "npm:^0.33.3" toml: "npm:^3.0.0" @@ -84,6 +74,14 @@ __metadata: languageName: unknown linkType: soft +"@cvmts/jpegturbo-rs@npm:*, @cvmts/jpegturbo-rs@workspace:jpegturbo-rs": + version: 0.0.0-use.local + resolution: "@cvmts/jpegturbo-rs@workspace:jpegturbo-rs" + dependencies: + cargo-cp-artifact: "npm:^0.1" + languageName: unknown + linkType: soft + "@cvmts/qemu@npm:*, @cvmts/qemu@workspace:qemu": version: 0.0.0-use.local resolution: "@cvmts/qemu@workspace:qemu" @@ -1643,23 +1641,6 @@ __metadata: languageName: node linkType: hard -"aproba@npm:^1.0.3 || ^2.0.0": - version: 2.0.0 - resolution: "aproba@npm:2.0.0" - checksum: 10c0/d06e26384a8f6245d8c8896e138c0388824e259a329e0c9f196b4fa533c82502a6fd449586e3604950a0c42921832a458bb3aa0aa9f0ba449cfd4f50fd0d09b5 - languageName: node - linkType: hard - -"are-we-there-yet@npm:^3.0.0": - version: 3.0.1 - resolution: "are-we-there-yet@npm:3.0.1" - dependencies: - delegates: "npm:^1.0.0" - readable-stream: "npm:^3.6.0" - checksum: 10c0/8373f289ba42e4b5ec713bb585acdac14b5702c75f2a458dc985b9e4fa5762bc5b46b40a21b72418a3ed0cfb5e35bdc317ef1ae132f3035f633d581dd03168c3 - languageName: node - linkType: hard - "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" @@ -1667,24 +1648,6 @@ __metadata: languageName: node linkType: hard -"asynckit@npm:^0.4.0": - version: 0.4.0 - resolution: "asynckit@npm:0.4.0" - checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d - languageName: node - linkType: hard - -"axios@npm:^1.6.5": - version: 1.6.8 - resolution: "axios@npm:1.6.8" - dependencies: - follow-redirects: "npm:^1.15.6" - form-data: "npm:^4.0.0" - proxy-from-env: "npm:^1.1.0" - checksum: 10c0/0f22da6f490335479a89878bc7d5a1419484fbb437b564a80c34888fc36759ae4f56ea28d55a191695e5ed327f0bad56e7ff60fb6770c14d1be6501505d47ab9 - languageName: node - linkType: hard - "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -1851,17 +1814,6 @@ __metadata: languageName: node linkType: hard -"cliui@npm:^8.0.1": - version: 8.0.1 - resolution: "cliui@npm:8.0.1" - dependencies: - string-width: "npm:^4.2.0" - strip-ansi: "npm:^6.0.1" - wrap-ansi: "npm:^7.0.0" - checksum: 10c0/4bda0f09c340cbb6dfdc1ed508b3ca080f12992c18d68c6be4d9cf51756033d5266e61ec57529e610dacbf4da1c634423b0c1b11037709cc6b09045cbd815df5 - languageName: node - linkType: hard - "clone@npm:^2.1.1": version: 2.1.2 resolution: "clone@npm:2.1.2" @@ -1869,29 +1821,6 @@ __metadata: languageName: node linkType: hard -"cmake-js@npm:^7.2.0": - version: 7.3.0 - resolution: "cmake-js@npm:7.3.0" - dependencies: - axios: "npm:^1.6.5" - debug: "npm:^4" - fs-extra: "npm:^11.2.0" - lodash.isplainobject: "npm:^4.0.6" - memory-stream: "npm:^1.0.0" - node-api-headers: "npm:^1.1.0" - npmlog: "npm:^6.0.2" - rc: "npm:^1.2.7" - semver: "npm:^7.5.4" - tar: "npm:^6.2.0" - url-join: "npm:^4.0.1" - which: "npm:^2.0.2" - yargs: "npm:^17.7.2" - bin: - cmake-js: bin/cmake-js - checksum: 10c0/8aa3839603578e3f40bff55a3b7cb962682223ab91bab82501289d6ee0b84246c22ecdc01381b38079a0f20fd5c6ca01068e928bf399f8054a19a7cdaab1060c - languageName: node - linkType: hard - "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -1934,15 +1863,6 @@ __metadata: languageName: node linkType: hard -"color-support@npm:^1.1.3": - version: 1.1.3 - resolution: "color-support@npm:1.1.3" - bin: - color-support: bin.js - checksum: 10c0/8ffeaa270a784dc382f62d9be0a98581db43e11eee301af14734a6d089bd456478b1a8b3e7db7ca7dc5b18a75f828f775c44074020b51c05fc00e6d0992b1cc6 - languageName: node - linkType: hard - "color@npm:^4.2.3": version: 4.2.3 resolution: "color@npm:4.2.3" @@ -1953,15 +1873,6 @@ __metadata: languageName: node linkType: hard -"combined-stream@npm:^1.0.8": - version: 1.0.8 - resolution: "combined-stream@npm:1.0.8" - dependencies: - delayed-stream: "npm:~1.0.0" - checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 - languageName: node - linkType: hard - "commander@npm:^7.0.0, commander@npm:^7.2.0": version: 7.2.0 resolution: "commander@npm:7.2.0" @@ -1969,13 +1880,6 @@ __metadata: languageName: node linkType: hard -"console-control-strings@npm:^1.1.0": - version: 1.1.0 - resolution: "console-control-strings@npm:1.1.0" - checksum: 10c0/7ab51d30b52d461412cd467721bb82afe695da78fff8f29fe6f6b9cbaac9a2328e27a22a966014df9532100f6dd85370460be8130b9c677891ba36d96a343f50 - languageName: node - linkType: hard - "cosmiconfig@npm:^8.0.0": version: 8.3.6 resolution: "cosmiconfig@npm:8.3.6" @@ -2057,7 +1961,7 @@ __metadata: languageName: unknown linkType: soft -"debug@npm:4, debug@npm:^4, debug@npm:^4.3.4": +"debug@npm:4, debug@npm:^4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -2069,27 +1973,6 @@ __metadata: languageName: node linkType: hard -"deep-extend@npm:^0.6.0": - version: 0.6.0 - resolution: "deep-extend@npm:0.6.0" - checksum: 10c0/1c6b0abcdb901e13a44c7d699116d3d4279fdb261983122a3783e7273844d5f2537dc2e1c454a23fcf645917f93fbf8d07101c1d03c015a87faa662755212566 - languageName: node - linkType: hard - -"delayed-stream@npm:~1.0.0": - version: 1.0.0 - resolution: "delayed-stream@npm:1.0.0" - checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 - languageName: node - linkType: hard - -"delegates@npm:^1.0.0": - version: 1.0.0 - resolution: "delegates@npm:1.0.0" - checksum: 10c0/ba05874b91148e1db4bf254750c042bf2215febd23a6d3cda2e64896aef79745fbd4b9996488bd3cafb39ce19dbce0fd6e3b6665275638befffe1c9b312b91b5 - languageName: node - linkType: hard - "detect-libc@npm:^1.0.3": version: 1.0.3 resolution: "detect-libc@npm:1.0.3" @@ -2279,16 +2162,6 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.15.6": - version: 1.15.6 - resolution: "follow-redirects@npm:1.15.6" - peerDependenciesMeta: - debug: - optional: true - checksum: 10c0/9ff767f0d7be6aa6870c82ac79cf0368cd73e01bbc00e9eb1c2a16fbb198ec105e3c9b6628bb98e9f3ac66fe29a957b9645bcb9a490bb7aa0d35f908b6b85071 - languageName: node - linkType: hard - "foreground-child@npm:^3.1.0": version: 3.1.1 resolution: "foreground-child@npm:3.1.1" @@ -2299,28 +2172,6 @@ __metadata: languageName: node linkType: hard -"form-data@npm:^4.0.0": - version: 4.0.0 - resolution: "form-data@npm:4.0.0" - dependencies: - asynckit: "npm:^0.4.0" - combined-stream: "npm:^1.0.8" - mime-types: "npm:^2.1.12" - checksum: 10c0/cb6f3ac49180be03ff07ba3ff125f9eba2ff0b277fb33c7fc47569fc5e616882c5b1c69b9904c4c4187e97dd0419dd03b134174756f296dec62041e6527e2c6e - languageName: node - linkType: hard - -"fs-extra@npm:^11.2.0": - version: 11.2.0 - resolution: "fs-extra@npm:11.2.0" - dependencies: - graceful-fs: "npm:^4.2.0" - jsonfile: "npm:^6.0.1" - universalify: "npm:^2.0.0" - checksum: 10c0/d77a9a9efe60532d2e790e938c81a02c1b24904ef7a3efb3990b835514465ba720e99a6ea56fd5e2db53b4695319b644d76d5a0e9988a2beef80aa7b1da63398 - languageName: node - linkType: hard - "fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -2358,29 +2209,6 @@ __metadata: languageName: node linkType: hard -"gauge@npm:^4.0.3": - version: 4.0.4 - resolution: "gauge@npm:4.0.4" - dependencies: - aproba: "npm:^1.0.3 || ^2.0.0" - color-support: "npm:^1.1.3" - console-control-strings: "npm:^1.1.0" - has-unicode: "npm:^2.0.1" - signal-exit: "npm:^3.0.7" - string-width: "npm:^4.2.3" - strip-ansi: "npm:^6.0.1" - wide-align: "npm:^1.1.5" - checksum: 10c0/ef10d7981113d69225135f994c9f8c4369d945e64a8fc721d655a3a38421b738c9fe899951721d1b47b73c41fdb5404ac87cc8903b2ecbed95d2800363e7e58c - languageName: node - linkType: hard - -"get-caller-file@npm:^2.0.5": - version: 2.0.5 - resolution: "get-caller-file@npm:2.0.5" - checksum: 10c0/c6c7b60271931fa752aeb92f2b47e355eac1af3a2673f47c9589e8f8a41adc74d45551c1bc57b5e66a80609f10ffb72b6f575e4370d61cc3f7f3aaff01757cde - languageName: node - linkType: hard - "get-port@npm:^4.2.0": version: 4.2.0 resolution: "get-port@npm:4.2.0" @@ -2428,7 +2256,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": +"graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 @@ -2449,13 +2277,6 @@ __metadata: languageName: node linkType: hard -"has-unicode@npm:^2.0.1": - version: 2.0.1 - resolution: "has-unicode@npm:2.0.1" - checksum: 10c0/ebdb2f4895c26bb08a8a100b62d362e49b2190bcfd84b76bc4be1a3bd4d254ec52d0dd9f2fbcc093fc5eb878b20c52146f9dfd33e2686ed28982187be593b47c - languageName: node - linkType: hard - "htmlnano@npm:^2.0.0": version: 2.1.0 resolution: "htmlnano@npm:2.1.0" @@ -2579,20 +2400,6 @@ __metadata: languageName: node linkType: hard -"inherits@npm:^2.0.3": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 - languageName: node - linkType: hard - -"ini@npm:~1.3.0": - version: 1.3.8 - resolution: "ini@npm:1.3.8" - checksum: 10c0/ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a - languageName: node - linkType: hard - "ip-address@npm:^9.0.5": version: 9.0.5 resolution: "ip-address@npm:9.0.5" @@ -2745,19 +2552,6 @@ __metadata: languageName: node linkType: hard -"jsonfile@npm:^6.0.1": - version: 6.1.0 - resolution: "jsonfile@npm:6.1.0" - dependencies: - graceful-fs: "npm:^4.1.6" - universalify: "npm:^2.0.0" - dependenciesMeta: - graceful-fs: - optional: true - checksum: 10c0/4f95b5e8a5622b1e9e8f33c96b7ef3158122f595998114d1e7f03985649ea99cb3cd99ce1ed1831ae94c8c8543ab45ebd044207612f31a56fd08462140e46865 - languageName: node - linkType: hard - "lightningcss-darwin-arm64@npm:1.24.1": version: 1.24.1 resolution: "lightningcss-darwin-arm64@npm:1.24.1" @@ -2900,13 +2694,6 @@ __metadata: languageName: node linkType: hard -"lodash.isplainobject@npm:^4.0.6": - version: 4.0.6 - resolution: "lodash.isplainobject@npm:4.0.6" - checksum: 10c0/afd70b5c450d1e09f32a737bed06ff85b873ecd3d3d3400458725283e3f2e0bb6bf48e67dbe7a309eb371a822b16a26cca4a63c8c52db3fc7dc9d5f9dd324cbb - languageName: node - linkType: hard - "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.2.0 resolution: "lru-cache@npm:10.2.0" @@ -2949,15 +2736,6 @@ __metadata: languageName: node linkType: hard -"memory-stream@npm:^1.0.0": - version: 1.0.0 - resolution: "memory-stream@npm:1.0.0" - dependencies: - readable-stream: "npm:^3.4.0" - checksum: 10c0/a2d9abd35845b228055ce5424dbdd8478711ba41325d02e6c8ef9baeba557287d4493a6e74d3db5c9849c58ea13fdc1dd445c96f469cbd02f47d22cfba930306 - languageName: node - linkType: hard - "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" @@ -2975,22 +2753,6 @@ __metadata: languageName: node linkType: hard -"mime-db@npm:1.52.0": - version: 1.52.0 - resolution: "mime-db@npm:1.52.0" - checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa - languageName: node - linkType: hard - -"mime-types@npm:^2.1.12": - version: 2.1.35 - resolution: "mime-types@npm:2.1.35" - dependencies: - mime-db: "npm:1.52.0" - checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 - languageName: node - linkType: hard - "mimic-fn@npm:^4.0.0": version: 4.0.0 resolution: "mimic-fn@npm:4.0.0" @@ -3007,13 +2769,6 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0": - version: 1.2.8 - resolution: "minimist@npm:1.2.8" - checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 - languageName: node - linkType: hard - "minipass-collect@npm:^2.0.1": version: 2.0.1 resolution: "minipass-collect@npm:2.0.1" @@ -3173,27 +2928,7 @@ __metadata: languageName: node linkType: hard -"nice-napi@npm:^1.0.2": - version: 1.0.2 - resolution: "nice-napi@npm:1.0.2" - dependencies: - node-addon-api: "npm:^3.0.0" - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.2.2" - conditions: "!os=win32" - languageName: node - linkType: hard - -"node-addon-api@npm:^3.0.0": - version: 3.2.1 - resolution: "node-addon-api@npm:3.2.1" - dependencies: - node-gyp: "npm:latest" - checksum: 10c0/41f21c9d12318875a2c429befd06070ce367065a3ef02952cfd4ea17ef69fa14012732f510b82b226e99c254da8d671847ea018cad785f839a5366e02dd56302 - languageName: node - linkType: hard - -"node-addon-api@npm:^6.0.0, node-addon-api@npm:^6.1.0": +"node-addon-api@npm:^6.1.0": version: 6.1.0 resolution: "node-addon-api@npm:6.1.0" dependencies: @@ -3211,13 +2946,6 @@ __metadata: languageName: node linkType: hard -"node-api-headers@npm:^1.1.0": - version: 1.1.0 - resolution: "node-api-headers@npm:1.1.0" - checksum: 10c0/7806d71077348ea199034e8c90a9147038d37fcccc1b85717e48c095fe31783a4f909f5daced4506e6cbce93fba91220bb3fc8626ee0640d26de9860f6500174 - languageName: node - linkType: hard - "node-gyp-build-optional-packages@npm:5.0.7": version: 5.0.7 resolution: "node-gyp-build-optional-packages@npm:5.0.7" @@ -3242,17 +2970,6 @@ __metadata: languageName: node linkType: hard -"node-gyp-build@npm:^4.2.2": - version: 4.8.0 - resolution: "node-gyp-build@npm:4.8.0" - bin: - node-gyp-build: bin.js - node-gyp-build-optional: optional.js - node-gyp-build-test: build-test.js - checksum: 10c0/85324be16f81f0235cbbc42e3eceaeb1b5ab94c8d8f5236755e1435b4908338c65a4e75f66ee343cbcb44ddf9b52a428755bec16dcd983295be4458d95c8e1ad - languageName: node - linkType: hard - "node-gyp@npm:latest": version: 10.1.0 resolution: "node-gyp@npm:10.1.0" @@ -3307,18 +3024,6 @@ __metadata: languageName: node linkType: hard -"npmlog@npm:^6.0.2": - version: 6.0.2 - resolution: "npmlog@npm:6.0.2" - dependencies: - are-we-there-yet: "npm:^3.0.0" - console-control-strings: "npm:^1.1.0" - gauge: "npm:^4.0.3" - set-blocking: "npm:^2.0.0" - checksum: 10c0/0cacedfbc2f6139c746d9cd4a85f62718435ad0ca4a2d6459cd331dd33ae58206e91a0742c1558634efcde3f33f8e8e7fd3adf1bfe7978310cf00bd55cccf890 - languageName: node - linkType: hard - "nth-check@npm:^2.0.1": version: 2.1.1 resolution: "nth-check@npm:2.1.1" @@ -3457,18 +3162,6 @@ __metadata: languageName: node linkType: hard -"piscina@npm:^4.4.0": - version: 4.4.0 - resolution: "piscina@npm:4.4.0" - dependencies: - nice-napi: "npm:^1.0.2" - dependenciesMeta: - nice-napi: - optional: true - checksum: 10c0/df6c2a2b673b0633a625f8dfc32f4519155e74ee24e31be9e69d2937e76d6cec8640278b4a50195652a943cccf8c634ed406f08598933c57e959d242b5fe5d1d - languageName: node - linkType: hard - "postcss-value-parser@npm:^4.2.0": version: 4.2.0 resolution: "postcss-value-parser@npm:4.2.0" @@ -3539,27 +3232,6 @@ __metadata: languageName: node linkType: hard -"proxy-from-env@npm:^1.1.0": - version: 1.1.0 - resolution: "proxy-from-env@npm:1.1.0" - checksum: 10c0/fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b - languageName: node - linkType: hard - -"rc@npm:^1.2.7": - version: 1.2.8 - resolution: "rc@npm:1.2.8" - dependencies: - deep-extend: "npm:^0.6.0" - ini: "npm:~1.3.0" - minimist: "npm:^1.2.0" - strip-json-comments: "npm:~2.0.1" - bin: - rc: ./cli.js - checksum: 10c0/24a07653150f0d9ac7168e52943cc3cb4b7a22c0e43c7dff3219977c2fdca5a2760a304a029c20811a0e79d351f57d46c9bde216193a0f73978496afc2b85b15 - languageName: node - linkType: hard - "react-error-overlay@npm:6.0.9": version: 6.0.9 resolution: "react-error-overlay@npm:6.0.9" @@ -3574,17 +3246,6 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": - version: 3.6.2 - resolution: "readable-stream@npm:3.6.2" - dependencies: - inherits: "npm:^2.0.3" - string_decoder: "npm:^1.1.1" - util-deprecate: "npm:^1.0.1" - checksum: 10c0/e37be5c79c376fdd088a45fa31ea2e423e5d48854be7a22a58869b4e84d25047b193f6acb54f1012331e1bcd667ffb569c01b99d36b0bd59658fb33f513511b7 - languageName: node - linkType: hard - "readdirp@npm:~3.6.0": version: 3.6.0 resolution: "readdirp@npm:3.6.0" @@ -3601,13 +3262,6 @@ __metadata: languageName: node linkType: hard -"require-directory@npm:^2.1.1": - version: 2.1.1 - resolution: "require-directory@npm:2.1.1" - checksum: 10c0/83aa76a7bc1531f68d92c75a2ca2f54f1b01463cb566cf3fbc787d0de8be30c9dbc211d1d46be3497dac5785fe296f2dd11d531945ac29730643357978966e99 - languageName: node - linkType: hard - "resolve-from@npm:^4.0.0": version: 4.0.0 resolution: "resolve-from@npm:4.0.0" @@ -3622,7 +3276,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:^5.0.1, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:^5.0.1": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 @@ -3649,7 +3303,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.5, semver@npm:^7.5.2, semver@npm:^7.5.4, semver@npm:^7.6.0": +"semver@npm:^7.3.5, semver@npm:^7.5.2, semver@npm:^7.6.0": version: 7.6.0 resolution: "semver@npm:7.6.0" dependencies: @@ -3660,13 +3314,6 @@ __metadata: languageName: node linkType: hard -"set-blocking@npm:^2.0.0": - version: 2.0.0 - resolution: "set-blocking@npm:2.0.0" - checksum: 10c0/9f8c1b2d800800d0b589de1477c753492de5c1548d4ade52f57f1d1f5e04af5481554d75ce5e5c43d4004b80a3eb714398d6907027dc0534177b7539119f4454 - languageName: node - linkType: hard - "sharp@npm:^0.33.3": version: 0.33.3 resolution: "sharp@npm:0.33.3" @@ -3752,13 +3399,6 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^3.0.7": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 - languageName: node - linkType: hard - "signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" @@ -3856,7 +3496,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -3878,15 +3518,6 @@ __metadata: languageName: node linkType: hard -"string_decoder@npm:^1.1.1": - version: 1.3.0 - resolution: "string_decoder@npm:1.3.0" - dependencies: - safe-buffer: "npm:~5.2.0" - checksum: 10c0/810614ddb030e271cd591935dcd5956b2410dd079d64ff92a1844d6b7588bf992b3e1b69b0f4d34a3e06e0bd73046ac646b5264c1987b20d0601f81ef35d731d - languageName: node - linkType: hard - "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -3912,13 +3543,6 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:~2.0.1": - version: 2.0.1 - resolution: "strip-json-comments@npm:2.0.1" - checksum: 10c0/b509231cbdee45064ff4f9fd73609e2bcc4e84a4d508e9dd0f31f70356473fde18abfb5838c17d56fb236f5a06b102ef115438de0600b749e818a35fbbc48c43 - languageName: node - linkType: hard - "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -3954,7 +3578,7 @@ __metadata: languageName: node linkType: hard -"tar@npm:^6.1.11, tar@npm:^6.1.2, tar@npm:^6.2.0": +"tar@npm:^6.1.11, tar@npm:^6.1.2": version: 6.2.1 resolution: "tar@npm:6.2.1" dependencies: @@ -4084,13 +3708,6 @@ __metadata: languageName: node linkType: hard -"universalify@npm:^2.0.0": - version: 2.0.1 - resolution: "universalify@npm:2.0.1" - checksum: 10c0/73e8ee3809041ca8b818efb141801a1004e3fc0002727f1531f4de613ea281b494a40909596dae4a042a4fb6cd385af5d4db2e137b1362e0e91384b828effd3a - languageName: node - linkType: hard - "update-browserslist-db@npm:^1.0.13": version: 1.0.13 resolution: "update-browserslist-db@npm:1.0.13" @@ -4105,20 +3722,6 @@ __metadata: languageName: node linkType: hard -"url-join@npm:^4.0.1": - version: 4.0.1 - resolution: "url-join@npm:4.0.1" - checksum: 10c0/ac65e2c7c562d7b49b68edddcf55385d3e922bc1dd5d90419ea40b53b6de1607d1e45ceb71efb9d60da02c681d13c6cb3a1aa8b13fc0c989dfc219df97ee992d - languageName: node - linkType: hard - -"util-deprecate@npm:^1.0.1": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 - languageName: node - linkType: hard - "utility-types@npm:^3.10.0": version: 3.11.0 resolution: "utility-types@npm:3.11.0" @@ -4133,7 +3736,7 @@ __metadata: languageName: node linkType: hard -"which@npm:^2.0.1, which@npm:^2.0.2": +"which@npm:^2.0.1": version: 2.0.2 resolution: "which@npm:2.0.2" dependencies: @@ -4155,16 +3758,7 @@ __metadata: languageName: node linkType: hard -"wide-align@npm:^1.1.5": - version: 1.1.5 - resolution: "wide-align@npm:1.1.5" - dependencies: - string-width: "npm:^1.0.2 || 2 || 3 || 4" - checksum: 10c0/1d9c2a3e36dfb09832f38e2e699c367ef190f96b82c71f809bc0822c306f5379df87bab47bed27ea99106d86447e50eb972d3c516c2f95782807a9d082fbea95 - languageName: node - linkType: hard - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" dependencies: @@ -4201,38 +3795,9 @@ __metadata: languageName: node linkType: hard -"y18n@npm:^5.0.5": - version: 5.0.8 - resolution: "y18n@npm:5.0.8" - checksum: 10c0/4df2842c36e468590c3691c894bc9cdbac41f520566e76e24f59401ba7d8b4811eb1e34524d57e54bc6d864bcb66baab7ffd9ca42bf1eda596618f9162b91249 - languageName: node - linkType: hard - "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a languageName: node linkType: hard - -"yargs-parser@npm:^21.1.1": - version: 21.1.1 - resolution: "yargs-parser@npm:21.1.1" - checksum: 10c0/f84b5e48169479d2f402239c59f084cfd1c3acc197a05c59b98bab067452e6b3ea46d4dd8ba2985ba7b3d32a343d77df0debd6b343e5dae3da2aab2cdf5886b2 - languageName: node - linkType: hard - -"yargs@npm:^17.7.2": - version: 17.7.2 - resolution: "yargs@npm:17.7.2" - dependencies: - cliui: "npm:^8.0.1" - escalade: "npm:^3.1.1" - get-caller-file: "npm:^2.0.5" - require-directory: "npm:^2.1.1" - string-width: "npm:^4.2.3" - y18n: "npm:^5.0.5" - yargs-parser: "npm:^21.1.1" - checksum: 10c0/ccd7e723e61ad5965fffbb791366db689572b80cca80e0f96aad968dfff4156cd7cd1ad18607afe1046d8241e6fb2d6c08bf7fa7bfb5eaec818735d8feac8f05 - languageName: node - linkType: hard