From 7e368df81285d076ed8f1e7cf96124054b08b9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Ml=C3=A1dek?= Date: Sun, 21 Apr 2024 12:13:26 +0200 Subject: [PATCH] WIP --- Earthfile | 71 +++++++-- cli/Cargo.toml | 33 ++-- cli/src/main.rs | 8 +- cli/src/plugins/host.rs | 13 ++ cli/src/plugins/mod.rs | 175 +++++++++++++++++++++ cli/src/routes.rs | 41 +++++ cli/src/serve.rs | 3 +- extensions/.gitignore | 1 + extensions/Cargo.lock | 299 ++++++++++++++++++++++++++++++++++++ extensions/Cargo.toml | 3 + extensions/base/Cargo.toml | 10 ++ extensions/base/src/lib.rs | 14 ++ extensions/dummy/Cargo.toml | 18 +++ extensions/dummy/build.rs | 3 + extensions/dummy/src/lib.rs | 14 ++ 15 files changed, 675 insertions(+), 31 deletions(-) create mode 100644 cli/src/plugins/host.rs create mode 100644 cli/src/plugins/mod.rs create mode 100644 extensions/.gitignore create mode 100644 extensions/Cargo.lock create mode 100644 extensions/Cargo.toml create mode 100644 extensions/base/Cargo.toml create mode 100644 extensions/base/src/lib.rs create mode 100644 extensions/dummy/Cargo.toml create mode 100644 extensions/dummy/build.rs create mode 100644 extensions/dummy/src/lib.rs diff --git a/Earthfile b/Earthfile index 2fe4a46..d115777 100644 --- a/Earthfile +++ b/Earthfile @@ -184,16 +184,17 @@ test: END test-backend: - FROM +base-backend - CACHE --id=rust-target target + FROM +base-rust RUN cargo nextest run --workspace -test-jslib: - FROM +base-node - WORKDIR sdks/js - RUN pnpm build && pnpm test - -# Deployment targets +appimage-signed: + FROM alpine + RUN apk add gpg gpg-agent + RUN --secret GPG_SIGN_KEY echo "$GPG_SIGN_KEY" | gpg --import + COPY +appimage/*.AppImage . + RUN gpg --clear-sign *.AppImage + SAVE ARTIFACT *.AppImage + SAVE ARTIFACT *.asc deploy-appimage-nightly: FROM alpine @@ -239,6 +240,40 @@ NPM_PUBLISH: ELSE RUN echo "Nothing to do for $pkg_name." END + +# Extensions (WIP) + +extensions: + WAIT + BUILD +extensions-dummy + END + +extensions-dummy: + FROM +base-extensions + WORKDIR dummy + RUN cargo build --release --target wasm32-unknown-unknown + SAVE ARTIFACT ../target/wasm32-unknown-unknown/release/upend_plugin_dummy.wasm + +extensions-dummy-signed: + FROM +base-sign + COPY +extensions-dummy/upend_plugin_dummy.wasm . + RUN gpg --detach-sign --sign --armor upend_plugin_dummy.wasm + SAVE ARTIFACT upend_plugin_dummy.wasm + SAVE ARTIFACT upend_plugin_dummy.wasm.asc + +base-extensions: + FROM rust:bookworm + RUN rustup component add clippy + RUN curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C /usr/local/cargo/bin + RUN cargo install wasm-pack wasm-bindgen-cli && rustup target add wasm32-unknown-unknown + WORKDIR /upend/extensions + COPY extensions/Cargo.toml Cargo.toml + COPY extensions/Cargo.lock Cargo.lock + COPY extensions/base/Cargo.toml base/Cargo.toml + COPY extensions/dummy/Cargo.toml dummy/Cargo.toml + RUN cargo fetch --locked + COPY --dir extensions/base ./ + COPY --dir extensions/dummy ./ # Utility targets @@ -253,11 +288,21 @@ git-version: RUN ./build/get_version.sh > /tmp/upend_version.txt && cat /tmp/upend_version.txt SAVE ARTIFACT /tmp/upend_version.txt version.txt -changelog: - FROM orhunp/git-cliff - COPY .git .git - RUN git-cliff --bump -o CHANGELOG.md - SAVE ARTIFACT CHANGELOG.md +base-rust: + FROM rust:bookworm + RUN rustup component add clippy + RUN curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C /usr/local/cargo/bin + RUN cargo install wasm-pack wasm-bindgen-cli && rustup target add wasm32-unknown-unknown + RUN cargo install cargo-audit + WORKDIR /upend + COPY Cargo.toml Cargo.lock . + COPY base/Cargo.toml base/Cargo.toml + COPY cli/Cargo.toml cli/Cargo.toml + COPY db/Cargo.toml db/Cargo.toml + COPY tools/upend_wasm/Cargo.toml tools/upend_wasm/Cargo.toml + RUN cargo fetch --locked + COPY --dir base cli db Cargo.toml Cargo.lock . + COPY --dir tools/upend_wasm tools/ current-changelog: FROM orhunp/git-cliff diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 4c2cbbd..5b9658e 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -29,10 +29,10 @@ once_cell = "1.7.2" lru = "0.7.0" diesel = { version = "1.4", features = [ - "sqlite", - "r2d2", - "chrono", - "serde_json", + "sqlite", + "r2d2", + "chrono", + "serde_json", ] } diesel_migrations = "1.4" libsqlite3-sys = { version = "^0", features = ["bundled"] } @@ -54,10 +54,10 @@ regex = "1" multibase = "0.9" multihash = { version = "*", default-features = false, features = [ - "alloc", - "multihash-impl", - "sha2", - "identity", + "alloc", + "multihash-impl", + "sha2", + "identity", ] } uuid = { version = "1.4", features = ["v4"] } @@ -91,18 +91,21 @@ bytes = "1.4.0" signal-hook = "0.3.15" actix-web-lab = { version = "0.20.2", features = ["spa"] } +extism = "1.2.0" +upend-extension-base = { path = "../extensions/base" } + [build-dependencies] shadow-rs = { version = "0.23", default-features = false } [features] default = [ - "desktop", - "previews", - "previews-image", - "extractors-web", - "extractors-audio", - "extractors-exif", - "extractors-media", + "desktop", + "previews", + "previews-image", + "extractors-web", + "extractors-audio", + "extractors-exif", + "extractors-media", ] desktop = ["webbrowser", "opener", "is_executable"] previews = [] diff --git a/cli/src/main.rs b/cli/src/main.rs index 2167751..234a8a4 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -36,8 +36,9 @@ mod routes; mod serve; mod util; -mod extractors; -mod previews; +mod extractors; // TODO REMOVE +mod plugins; +mod previews; // TODO REMOVE #[derive(Debug, Parser)] #[command(name = "upend", author)] @@ -394,12 +395,15 @@ async fn main() -> Result<()> { .collect() }); + let plugins = crate::plugins::Plugins::init(&get_resource_path("plugins")?)?; + let state = routes::State { upend: upend.clone(), store, job_container: job_container.clone(), preview_store, preview_thread_pool, + plugins: plugins.into(), config: UpEndConfig { vault_name: Some(args.vault_name.unwrap_or_else(|| { vault_path diff --git a/cli/src/plugins/host.rs b/cli/src/plugins/host.rs new file mode 100644 index 0000000..99ab181 --- /dev/null +++ b/cli/src/plugins/host.rs @@ -0,0 +1,13 @@ +use extism::{CurrentPlugin, UserData, Val}; +use upend_base::error::UpEndError; + +fn hello_world( + _plugin: &mut CurrentPlugin, + inputs: &[Val], + outputs: &mut [Val], + _user_data: UserData, +) -> Result<(), UpEndError> { + println!("Hello from Rust!"); + outputs[0] = inputs[0].clone(); + Ok(()) +} diff --git a/cli/src/plugins/mod.rs b/cli/src/plugins/mod.rs new file mode 100644 index 0000000..d40f450 --- /dev/null +++ b/cli/src/plugins/mod.rs @@ -0,0 +1,175 @@ +use anyhow::Result; +use extism::{manifest::Wasm, *}; +use std::{ + path::{Path, PathBuf}, + process::Command, +}; +use upend_extension_base::PluginInfo; + +mod host; +pub struct Plugins<'a> { + pub plugins: Vec>, +} + +#[derive(Debug)] +pub enum UpEndPlugin<'a> { + Initialized(UpEndPluginInitialized<'a>), + Failed(UpEndPluginFailed), +} +pub struct UpEndPluginInitialized<'a> { + pub path: PathBuf, + pub info: PluginInfo, + pub plugin: Box>, + pub verified: Result<(), String>, +} + +impl std::fmt::Debug for UpEndPluginInitialized<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("UpEndPluginInitialized") + .field("path", &self.path) + .field("info", &self.info) + .field("verified", &self.verified) + .finish() + } +} + +#[derive(Debug)] +pub struct UpEndPluginFailed { + pub path: PathBuf, + pub error: String, +} + +impl Plugins<'_> { + pub fn init(plugin_path: &Path) -> Result { + let plugin_files = plugin_path + .read_dir()? + .filter_map(|p| p.ok().and_then(|p| Some(p.path()))) + .filter(|p| p.is_file() && p.extension().unwrap_or_default() == "wasm"); + + let mut plugins = vec![]; + + for plugin_path in plugin_files { + debug!("Attempting to load plugin: {:?}", plugin_path); + let file = Wasm::file(plugin_path.clone()); + let manifest = Manifest::new([file]); + let plugin = Plugin::create_with_manifest(&manifest, [], true); + match plugin { + Ok(mut plugin) => { + debug!("Plugin loaded: {:?}", plugin_path); + let info = plugin.call("info", []).and_then(|v| { + serde_json::from_slice::(&v).map_err(|e| anyhow::anyhow!(e)) + }); + match info { + Ok(info) => { + debug!("Plugin info: {:?}", info); + + let mut gpg_cmd = Command::new("gpg"); + let verify_cmd = gpg_cmd + .arg("--verify") + .arg(&plugin_path.with_extension("wasm.asc")); + let verify_result = verify_cmd + .output() + .map_err(|e| format!("Failed to run gpg: {:?}", e)) + .and_then(|output| { + if output.status.success() { + Ok(()) + } else { + Err(format!( + "Failed to verify plugin: {:?}", + String::from_utf8_lossy(&output.stderr) + )) + } + }); + let verified = verify_result.and_then(|_| Ok(())); + + plugins.push(UpEndPlugin::Initialized(UpEndPluginInitialized { + path: plugin_path.clone(), + info, + plugin: Box::new(plugin), + verified, + })); + } + Err(e) => { + error!("Failed to get plugin info: {:?}", e); + plugins.push(UpEndPlugin::Failed(UpEndPluginFailed { + path: plugin_path.clone(), + error: format!("Failed to get plugin info: {:?}", e), + })); + } + } + } + Err(e) => { + error!("Failed to create plugin: {:?}", e); + plugins.push(UpEndPlugin::Failed(UpEndPluginFailed { + path: plugin_path.clone(), + error: format!("Failed to create plugin: {:?}", e), + })); + } + } + } + + Ok(Self { plugins }) + } +} + +#[cfg(test)] +mod tests { + use core::panic; + + use super::*; + use crate::common::get_resource_path; + + #[test] + fn test_plugins_init() { + let plugins = Plugins::init(&get_resource_path("plugins").unwrap()).unwrap(); + assert!(plugins.plugins.len() > 0); + for plugin in plugins.plugins { + assert!( + match plugin { + UpEndPlugin::Initialized(_) => true, + _ => false, + }, + "{:?}", + plugin + ); + } + } + + #[test] + fn test_plugins_verify() { + let plugins = Plugins::init(&get_resource_path("plugins").unwrap()).unwrap(); + let verified_plugin = plugins + .plugins + .iter() + .find(|p| match p { + UpEndPlugin::Initialized(p) => p.path.to_string_lossy().contains("verified"), + _ => false, + }) + .unwrap(); + assert!( + match verified_plugin { + UpEndPlugin::Initialized(p) => p.verified.is_ok(), + _ => false, + }, + "{:?}", + verified_plugin + ); + + let unverified_plugin = plugins + .plugins + .iter() + .find(|p| match p { + UpEndPlugin::Initialized(p) => !p.path.to_string_lossy().contains("verified"), + _ => false, + }) + .unwrap(); + assert!( + match unverified_plugin { + UpEndPlugin::Initialized(p) => p.verified.is_err(), + _ => false, + }, + "{:?}", + unverified_plugin + ); + } +} diff --git a/cli/src/routes.rs b/cli/src/routes.rs index f519033..014a8fe 100644 --- a/cli/src/routes.rs +++ b/cli/src/routes.rs @@ -2,6 +2,7 @@ use crate::common::build; use crate::common::REQWEST_CLIENT; use crate::config::UpEndConfig; use crate::extractors; +use crate::plugins::Plugins; use crate::previews::PreviewStore; use crate::util::exec::block_background; use actix_files::NamedFile; @@ -43,6 +44,7 @@ use upend_db::stores::{Blob, UpStore}; use upend_db::BlobMode; use upend_db::OperationContext; use upend_db::UpEndDatabase; +use upend_extension_base::PluginInfo; use upend_db::VaultOptions; use url::Url; @@ -55,6 +57,7 @@ pub struct State { pub upend: Arc, pub store: Arc>, pub config: UpEndConfig, + pub plugins: Arc>, pub job_container: jobs::JobContainer, pub preview_store: Option>, pub preview_thread_pool: Option>, @@ -1114,6 +1117,42 @@ pub async fn get_user_entries( Ok(HttpResponse::Ok().json(result.as_hash().map_err(ErrorInternalServerError)?)) } +#[derive(Serialize)] +pub struct Plugin { + name: String, + info: Option, + error: Option, +} + +#[get("/api/plugins")] +pub async fn get_plugins(state: web::Data) -> Result { + let plugins: Vec = state + .plugins + .clone() + .plugins + .iter() + .map(|p| match p { + crate::plugins::UpEndPlugin::Initialized(p) => Plugin { + name: p.info.name.clone(), + info: Some(p.info.clone()), + error: None, + }, + crate::plugins::UpEndPlugin::Failed(p) => Plugin { + name: p + .path + .components() + .last() + .map(|p| p.as_os_str().to_string_lossy().into_owned()) + .unwrap_or_else(|| "???".into()), + info: None, + error: Some(p.error.clone()), + }, + }) + .collect(); + + Ok(HttpResponse::Ok().json(plugins)) +} + #[derive(Debug)] enum ExternalFetchError { Status(anyhow::Error), @@ -1383,6 +1422,7 @@ mod tests { ) .unwrap(); + let plugins = Plugins { plugins: vec![] }; State { upend, store, @@ -1392,6 +1432,7 @@ mod tests { trust_executables: false, secret: "secret".to_string(), }, + plugins: plugins.into(), job_container, preview_store: None, preview_thread_pool: None, diff --git a/cli/src/serve.rs b/cli/src/serve.rs index 1789e54..e8a016b 100644 --- a/cli/src/serve.rs +++ b/cli/src/serve.rs @@ -69,7 +69,8 @@ where .service(routes::get_info) .service(routes::get_options) .service(routes::put_options) - .service(routes::get_user_entries); + .service(routes::get_user_entries) + .service(routes::get_plugins); if ui_enabled { return app.service( diff --git a/extensions/.gitignore b/extensions/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/extensions/.gitignore @@ -0,0 +1 @@ +target diff --git a/extensions/Cargo.lock b/extensions/Cargo.lock new file mode 100644 index 0000000..67a972d --- /dev/null +++ b/extensions/Cargo.lock @@ -0,0 +1,299 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "const_format" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "deranged" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "extism-manifest" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22b0e600ec289630715ffdc11aca36a26297c3ab7908f14d5bbf3770d102bce7" +dependencies = [ + "base64", + "serde", +] + +[[package]] +name = "extism-pdk" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c20fe9cafa572607e22192bf2040849e7456664895bdc589c89387876e2067" +dependencies = [ + "anyhow", + "base64", + "extism-manifest", + "extism-pdk-derive", + "rmp-serde", + "serde", + "serde_json", +] + +[[package]] +name = "extism-pdk-derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2be216330f7304de051e0faf1578880e9e0dc1ecbd2c0fea5765c63a079d0ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "is_debug" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06d198e9919d9822d5f7083ba8530e04de87841eaf21ead9af8f2304efd57c89" + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rmp" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "serde" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shadow-rs" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "970538704756fd0bb4ec8cb89f80674afb661e7c0fe716f9ba5be57717742300" +dependencies = [ + "const_format", + "is_debug", + "time", +] + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "itoa", + "libc", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "upend-extension-base" +version = "0.1.0" +dependencies = [ + "serde", +] + +[[package]] +name = "upend-plugin-dummy" +version = "0.0.0" +dependencies = [ + "extism-pdk", + "serde", + "shadow-rs", + "upend-extension-base", +] diff --git a/extensions/Cargo.toml b/extensions/Cargo.toml new file mode 100644 index 0000000..79bf56b --- /dev/null +++ b/extensions/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +members = ["base", "dummy"] +resolver = "2" diff --git a/extensions/base/Cargo.toml b/extensions/base/Cargo.toml new file mode 100644 index 0000000..2bddd90 --- /dev/null +++ b/extensions/base/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "upend-extension-base" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } diff --git a/extensions/base/src/lib.rs b/extensions/base/src/lib.rs new file mode 100644 index 0000000..f1897cd --- /dev/null +++ b/extensions/base/src/lib.rs @@ -0,0 +1,14 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PluginInfo { + pub name: String, + pub version: String, + pub r#type: PluginType, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum PluginType { + Extractor, + Transformer, +} diff --git a/extensions/dummy/Cargo.toml b/extensions/dummy/Cargo.toml new file mode 100644 index 0000000..9353182 --- /dev/null +++ b/extensions/dummy/Cargo.toml @@ -0,0 +1,18 @@ +[package] +edition = "2021" +name = "upend-plugin-dummy" +version = "0.0.0" +build = "build.rs" + +[lib] +path = "src/lib.rs" +crate_type = ["cdylib"] + +[dependencies] +extism-pdk = "1.1.0" +serde = "1.0.181" +upend-extension-base = { path = "../base", version = "0.1.0" } +shadow-rs = { version = "0.23", default-features = false } + +[build-dependencies] +shadow-rs = { version = "0.23", default-features = false } diff --git a/extensions/dummy/build.rs b/extensions/dummy/build.rs new file mode 100644 index 0000000..4a0dfc4 --- /dev/null +++ b/extensions/dummy/build.rs @@ -0,0 +1,3 @@ +fn main() -> shadow_rs::SdResult<()> { + shadow_rs::new() +} diff --git a/extensions/dummy/src/lib.rs b/extensions/dummy/src/lib.rs new file mode 100644 index 0000000..3496c7c --- /dev/null +++ b/extensions/dummy/src/lib.rs @@ -0,0 +1,14 @@ +use extism_pdk::*; +use shadow_rs::shadow; +use upend_extension_base::{PluginInfo, PluginType}; + +shadow!(build); + +#[plugin_fn] +pub fn info(_arg: ()) -> FnResult> { + Ok(Json(PluginInfo { + name: "Text".to_string(), + version: build::PKG_VERSION.to_string(), + r#type: PluginType::Transformer, + })) +}