diff --git a/.github/actions/build-test-wasm/action.yaml b/.github/actions/build-test-wasm/action.yaml new file mode 100644 index 0000000..0effdc1 --- /dev/null +++ b/.github/actions/build-test-wasm/action.yaml @@ -0,0 +1,31 @@ +name: 'Build/Test WASM' +description: 'A simple composite GitHub Action sets-up WASM; then test & build relevant crates' +inputs: + cate: + description: 'The crate name. Must be in ./crates' + required: true +runs: + using: 'composite' + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + - run: yarn install + shell: bash + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + shell: bash + - name: Build WASM + run: | + mkdir -p ./prebuilds/${{ inputs.crate }} + wasm-pack build --target nodejs ./crates/${{ inputs.crate }} --out-dir ../../prebuilds/${{ inputs.crate }} + shell: bash + - name: Test WASM + run: node test_wasm.js + shell: bash + - uses: actions/upload-artifact@v4 + with: + name: prebuilds-wasm + if-no-files-found: ignore + path: ./prebuilds/* diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1c85d4b..e534dc5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,8 +7,22 @@ on: - main jobs: + build-test-wasm: + runs-on: ubuntu-latest + strategy: + matrix: + crate: + - library_config + steps: + - uses: actions/checkout@v4 + - name: 'Use composite action' + uses: ./.github/actions/build-test-wasm + with: + crate: '${{ matrix.crate }}' + build: uses: Datadog/action-prebuildify/.github/workflows/build.yml@main + needs: build-test-wasm with: package-manager: 'yarn' cache: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f2982b..d9b1a7a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,8 +6,22 @@ on: - v0.x jobs: + build-test-wasm: + runs-on: ubuntu-latest + strategy: + matrix: + crate: + - library_config + steps: + - uses: actions/checkout@v4 + - name: 'Use composite action' + uses: ./.github/actions/build-test-wasm + with: + crate: '${{ matrix.crate }}' + build: uses: Datadog/action-prebuildify/.github/workflows/build.yml@main + needs: build-test-wasm with: package-manager: 'yarn' cache: false diff --git a/Cargo.lock b/Cargo.lock index c042060..25049a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -267,6 +267,16 @@ dependencies = [ "tokio", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "convert_case" version = "0.6.0" @@ -351,14 +361,14 @@ dependencies = [ [[package]] name = "datadog-crashtracker" -version = "14.3.1" -source = "git+https://github.com/DataDog/libdatadog.git?tag=v14.3.1#48240f2588665a03c2061879345566ec7e70fabf" +version = "15.0.0" +source = "git+https://github.com/DataDog/libdatadog.git?tag=v15.0.0#0ef49864317b0728648b2b7f26fe2f1deeeeebc4" dependencies = [ "anyhow", "backtrace", "blazesym", "chrono", - "ddcommon 14.3.1", + "ddcommon 15.0.0", "ddtelemetry", "http 0.2.12", "hyper 0.14.31", @@ -377,12 +387,22 @@ dependencies = [ [[package]] name = "datadog-ddsketch" -version = "14.3.1" -source = "git+https://github.com/DataDog/libdatadog.git?tag=v14.3.1#48240f2588665a03c2061879345566ec7e70fabf" +version = "15.0.0" +source = "git+https://github.com/DataDog/libdatadog.git?tag=v15.0.0#0ef49864317b0728648b2b7f26fe2f1deeeeebc4" dependencies = [ "prost", ] +[[package]] +name = "datadog-library-config" +version = "0.0.1" +source = "git+https://github.com/DataDog/libdatadog.git?tag=v15.0.0#0ef49864317b0728648b2b7f26fe2f1deeeeebc4" +dependencies = [ + "anyhow", + "serde", + "serde_yaml", +] + [[package]] name = "datadog-trace-normalization" version = "6.0.0" @@ -448,8 +468,8 @@ dependencies = [ [[package]] name = "ddcommon" -version = "14.3.1" -source = "git+https://github.com/DataDog/libdatadog.git?tag=v14.3.1#48240f2588665a03c2061879345566ec7e70fabf" +version = "15.0.0" +source = "git+https://github.com/DataDog/libdatadog.git?tag=v15.0.0#0ef49864317b0728648b2b7f26fe2f1deeeeebc4" dependencies = [ "anyhow", "cc", @@ -477,13 +497,13 @@ dependencies = [ [[package]] name = "ddtelemetry" -version = "14.3.1" -source = "git+https://github.com/DataDog/libdatadog.git?tag=v14.3.1#48240f2588665a03c2061879345566ec7e70fabf" +version = "15.0.0" +source = "git+https://github.com/DataDog/libdatadog.git?tag=v15.0.0#0ef49864317b0728648b2b7f26fe2f1deeeeebc4" dependencies = [ "anyhow", "base64 0.22.1", "datadog-ddsketch", - "ddcommon 14.3.1", + "ddcommon 15.0.0", "futures", "hashbrown 0.14.5", "http 0.2.12", @@ -979,6 +999,18 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "library-config" +version = "0.1.0" +dependencies = [ + "anyhow", + "datadog-library-config", + "serde", + "serde-wasm-bindgen", + "wasm-bindgen", + "wasm-bindgen-test", +] + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -1015,6 +1047,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "minicov" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1556,6 +1598,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.26" @@ -1589,6 +1640,12 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "sct" version = "0.7.1" @@ -1643,6 +1700,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_bytes" version = "0.11.15" @@ -1686,6 +1754,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1901,6 +1982,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.7.1" @@ -1929,6 +2016,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -1970,6 +2067,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.95" @@ -1999,6 +2108,32 @@ version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +[[package]] +name = "wasm-bindgen-test" +version = "0.3.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d381749acb0943d357dcbd8f0b100640679883fcdeeef04def49daf8d33a5426" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "minicov", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c97b2ef2c8d627381e51c071c2ab328eac606d3f69dd82bcbca20a9e389d95f0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "web-sys" version = "0.3.72" @@ -2047,6 +2182,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 7731b6c..b8ba21e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ default-members = [ "crates/crashtracker" ] members = [ - "crates/*" + "crates/*", ] [profile.release] diff --git a/crates/crashtracker/Cargo.toml b/crates/crashtracker/Cargo.toml index b381f41..b63261f 100644 --- a/crates/crashtracker/Cargo.toml +++ b/crates/crashtracker/Cargo.toml @@ -14,7 +14,7 @@ path = "src/bin/receiver.rs" [dependencies] anyhow = "1" -datadog-crashtracker = { git = "https://github.com/DataDog/libdatadog.git", tag = "v14.3.1" } +datadog-crashtracker = { git = "https://github.com/DataDog/libdatadog.git", tag = "v15.0.0" } napi = { version = "2", features = ["serde-json"] } napi-derive = { version = "2", default-features = false } rustls = { version = "*", default-features = false, features = ["aws-lc-rs"] } diff --git a/crates/library_config/Cargo.toml b/crates/library_config/Cargo.toml new file mode 100644 index 0000000..c5459ee --- /dev/null +++ b/crates/library_config/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "library-config" +version = "0.1.0" +edition = "2018" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +anyhow = "1" +datadog-library-config = { git = "https://github.com/DataDog/libdatadog.git", tag = "v15.0.0" } + +wasm-bindgen = "0.2.84" +serde = { version = "1.0", features = ["derive"] } +serde-wasm-bindgen = "0.4" + +[dev-dependencies] +wasm-bindgen-test = "0.3.34" diff --git a/crates/library_config/src/lib.rs b/crates/library_config/src/lib.rs new file mode 100644 index 0000000..897885b --- /dev/null +++ b/crates/library_config/src/lib.rs @@ -0,0 +1,79 @@ +use std::collections::HashMap; + +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct JsConfigurator { + configurator: Box, + envp: Vec, + args: Vec, +} + +#[wasm_bindgen] +impl JsConfigurator { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + JsConfigurator { + configurator: Box::new(datadog_library_config::Configurator::new(false)), // No debug log as WASM can't write to stdout + envp: Vec::new(), + args: Vec::new(), + } + } + + #[wasm_bindgen] + pub fn set_envp(&mut self, envp: Box<[JsValue]>) -> Result<(), JsValue> { + self.envp = envp.iter() + .filter_map(|val| val.as_string()) + .collect(); + Ok(()) + } + + #[wasm_bindgen] + pub fn set_args(&mut self, args: Box<[JsValue]>) -> Result<(), JsValue> { + self.args = args.iter() + .filter_map(|val| val.as_string()) + .collect(); + Ok(()) + } + + #[wasm_bindgen] + pub fn get_configuration( + &self, + config_string: String, + ) -> Result { + let envp: Vec<&[u8]> = self + .envp + .iter() + .map(|s| s.as_bytes()) + .collect(); + + let args: Vec<_> = self + .args + .iter() + .map(|s| s.as_bytes()) + .collect(); + + let res_config = self.configurator.get_config_from_bytes( + config_string.as_bytes(), + datadog_library_config::ProcessInfo { + envp: &envp, + args: &args, + language: b"nodejs", + }, + ); + + match res_config { + Ok(config) => { + let hashmap: HashMap = config.into_iter().map(|c| { + let key = c.name.to_str().to_owned(); + (key, c.value) + }).collect(); + Ok(serde_wasm_bindgen::to_value(&hashmap)?) + }, + Err(e) => Err(JsValue::from_str(&format!( + "Failed to get configuration: {:?}", + e + ))), + } + } +} diff --git a/load.js b/load.js index 6ce11fe..21970c3 100644 --- a/load.js +++ b/load.js @@ -24,12 +24,23 @@ function maybeLoad (name) { function load (name) { const filename = find(name) + const filenameWASM = findWASM(name) - if (!filename) { - throw new Error(`Could not find a ${name} binary for ${PLATFORM}${LIBC}-${ARCH}.`) + if (filename) { + return runtimeRequire(filename) + } else if (filenameWASM) { + return runtimeRequire(filenameWASM) } + throw new Error(`Could not find a ${name} binary for ${PLATFORM}${LIBC}-${ARCH} nor a ${name} WASM module.`) +} - return runtimeRequire(filename) +function findWASM (name) { + const root = __dirname + const prebuilds = path.join(root, 'prebuilds') + const folders = readdirSync(prebuilds) + if (folders.find(f => f === name)) { + return path.join(prebuilds, name, `${name}.js`) + } } function find (name, binary = false) { diff --git a/package.json b/package.json index d5bf907..897c058 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,12 @@ "description": "Node.js binding for libdatadog", "main": "index.js", "scripts": { - "build": "yarn -s build-debug", + "install-wasm-pack": "curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh", + "build": "yarn -s build-debug && yarn -s build-wasm", "build-debug": "mkdir -p target && yarn -s cargo-build > ./target/out.ndjson && yarn -s copy-artifacts", "build-release": "mkdir -p target && yarn -s cargo-build-release > ./target/out.ndjson && yarn -s copy-artifacts", - "build-all": "mkdir -p target && yarn -s cargo-build -- --workspace > ./target/out.ndjson && yarn -s copy-artifacts", + "build-all": "mkdir -p target && yarn -s cargo-build -- --workspace > ./target/out.ndjson && yarn -s copy-artifacts && yarn -s build-wasm", + "build-wasm": "yarn -s install-wasm-pack && wasm-pack build --target nodejs ./crates/library_config --out-dir ../../prebuilds/library_config", "cargo-build-release": "yarn -s cargo-build -- --release", "cargo-build": "cargo build --message-format=json-render-diagnostics", "copy-artifacts": "node ./scripts/copy-artifacts", diff --git a/test.js b/test.js index f451472..822f194 100644 --- a/test.js +++ b/test.js @@ -6,5 +6,7 @@ const { execSync } = require('child_process') fs.readdirSync('test') .filter(file => file.endsWith('.js') || !file.includes('.')) .forEach(file => { - require('./test/' + file) + if (!file.includes('wasm')) { + require('./test/' + file) + } }) diff --git a/test/wasm/library_config/.gitignore b/test/wasm/library_config/.gitignore new file mode 100644 index 0000000..5fff1d9 --- /dev/null +++ b/test/wasm/library_config/.gitignore @@ -0,0 +1 @@ +pkg diff --git a/test/wasm/library_config/README.md b/test/wasm/library_config/README.md new file mode 100644 index 0000000..4e58f07 --- /dev/null +++ b/test/wasm/library_config/README.md @@ -0,0 +1,8 @@ +# Libconfig example + +## How to run +From repository root +```bash +yarn build-wasm +node test/wasm/library_config/index.js +``` diff --git a/test/wasm/library_config/config.yaml b/test/wasm/library_config/config.yaml new file mode 100644 index 0000000..0bdcd11 --- /dev/null +++ b/test/wasm/library_config/config.yaml @@ -0,0 +1,8 @@ +rules: + - selectors: + - origin: language + matches: + - nodejs + operator: equals + configuration: + DD_SERVICE: my-service diff --git a/test/wasm/library_config/index.js b/test/wasm/library_config/index.js new file mode 100644 index 0000000..a5283e8 --- /dev/null +++ b/test/wasm/library_config/index.js @@ -0,0 +1,22 @@ +const path = require('path'); +const fs = require('fs'); +const loader = require('../../../load.js'); +const assert = require('assert'); + +const libconfig = loader.load('library_config'); +assert(libconfig !== undefined); + +const rawConfig = fs.readFileSync(path.join(__dirname, 'config.yaml')); +let configurator = new libconfig.JsConfigurator(); + +configurator.set_envp(Object.entries(process.env).map(([key, value]) => `${key}=${value}`)) +configurator.set_args(process.argv) + +// Apply each configuration as an environment variable +let values = {} +configurator.get_configuration(rawConfig.toString()).forEach((value, key, map) => { + values[key] = value + console.log(`Got ${key}=${value}`) +}); + +assert.strictEqual(values['DD_SERVICE'], 'my-service') diff --git a/test_wasm.js b/test_wasm.js new file mode 100644 index 0000000..762dd03 --- /dev/null +++ b/test_wasm.js @@ -0,0 +1,10 @@ +'use strict' + +const fs = require('fs') +const { execSync } = require('child_process') + +fs.readdirSync('test/wasm') + .filter(file => file.endsWith('.js') || !file.includes('.')) + .forEach(file => { + require('./test/wasm/' + file) + })