diff --git a/src/main.rs b/src/main.rs index 1a89568f..52d8d67a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ extern crate lazy_static; mod config; mod data; mod router; +mod runtimes; mod workers; use actix_files::{Files, NamedFile}; diff --git a/src/runtimes/metadata.rs b/src/runtimes/metadata.rs new file mode 100644 index 00000000..89e6f534 --- /dev/null +++ b/src/runtimes/metadata.rs @@ -0,0 +1,85 @@ +// Copyright 2022 VMware, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use super::{remote_file::RemoteFile, runtime::RuntimeStatus}; +use anyhow::{anyhow, Result}; +use serde::Deserialize; +use std::collections::HashMap; + +// TODO: Remove it when implementing the manager +#[allow(dead_code)] +/// Metadata associated to a Runtime. It contains information +/// about a certain runtime like name, version and all the +/// details to run workers with it. +/// +/// A runtime is a Wasm binary + configuration that can run +/// a source code as a worker. The configuration includes +/// different pieces like polyfills files, templates, +/// arguments, etc. +#[derive(Deserialize)] +pub struct RuntimeMetadata<'a> { + /// Name of the runtime (like ruby, python, etc) + name: &'a str, + /// Specific version of the runtime + version: &'a str, + /// Current status in the repository + status: RuntimeStatus, + /// Associated extensions + extensions: Vec<&'a str>, + /// Arguments to pass to the Wasm module via WASI + args: Vec<&'a str>, + /// A list of environment variables that must be configured + /// for the runtime to work. + envs: Option>, + /// The reference to a remote binary (url + checksum) + binary: RemoteFile<'a>, + /// The reference to a remote polyfill file (url + checksum) + polyfill: Option>, + /// The refernmece to a template file for the worker. It will wrap the + /// source code into a template that can include imports, + /// function calls, etc. + template: Option>, +} + +// TODO: Remove it when implementing the manager +#[allow(dead_code)] +impl<'a> RuntimeMetadata<'a> { + /// Reads and parses the metadata from a slice of bytes. It will return + /// a result as the deserialization may fail. + pub fn from_slice(data: &'a [u8]) -> Result { + toml::from_slice::(data) + .map_err(|_| anyhow!("wws could not deserialize the runtime metadata")) + } +} + +#[cfg(test)] +mod tests { + use crate::runtimes::remote_file::Checksum; + + use super::*; + use std::{any::Any, fs}; + + #[test] + fn parse_runtime_toml() { + let contents = fs::read("tests/data/metadata/runtime.toml").unwrap(); + let metadata = RuntimeMetadata::from_slice(&contents).unwrap(); + + assert_eq!(metadata.name, "ruby"); + assert_eq!(metadata.version, "3.2.0+20230118-8aec06d"); + assert_eq!(metadata.status.type_id(), RuntimeStatus::Active.type_id()); + assert_eq!(metadata.binary.url, "https://github.com/vmware-labs/webassembly-language-runtimes/releases/download/ruby%2F3.2.0%2B20230118-8aec06d/ruby-3.2.0.wasm"); + + let Checksum::Sha256 { value } = metadata.binary.checksum; + assert_eq!( + value, + "e2d91cff05ec59ed9c88aadbd3b477842092054bf24c5d944d5ad6dbafdd3b32" + ); + + // Optionals + let polyfill = metadata.polyfill.unwrap(); + assert_eq!( + polyfill.url, + "https://raw.githubusercontent.com/Angelmmiguel/wws-index-test/main/ruby/poly.rb" + ); + } +} diff --git a/src/runtimes/mod.rs b/src/runtimes/mod.rs new file mode 100644 index 00000000..c2303134 --- /dev/null +++ b/src/runtimes/mod.rs @@ -0,0 +1,8 @@ +// Copyright 2022 VMware, Inc. +// SPDX-License-Identifier: Apache-2.0 + +mod metadata; +mod modules; +mod remote_file; +mod repository; +pub mod runtime; diff --git a/src/workers/runtimes/data.rs b/src/runtimes/modules/data.rs similarity index 100% rename from src/workers/runtimes/data.rs rename to src/runtimes/modules/data.rs diff --git a/src/workers/runtimes/javascript.rs b/src/runtimes/modules/javascript.rs similarity index 98% rename from src/workers/runtimes/javascript.rs rename to src/runtimes/modules/javascript.rs index 77823ace..54aa9e68 100644 --- a/src/workers/runtimes/javascript.rs +++ b/src/runtimes/modules/javascript.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use super::data::Data; -use crate::workers::runtime::Runtime; +use crate::runtimes::runtime::Runtime; use anyhow::Result; use std::{fs, path::PathBuf}; use wasmtime_wasi::Dir; diff --git a/src/workers/runtimes/mod.rs b/src/runtimes/modules/mod.rs similarity index 100% rename from src/workers/runtimes/mod.rs rename to src/runtimes/modules/mod.rs diff --git a/src/workers/runtimes/native.rs b/src/runtimes/modules/native.rs similarity index 94% rename from src/workers/runtimes/native.rs rename to src/runtimes/modules/native.rs index d5ad370b..dd589ec7 100644 --- a/src/workers/runtimes/native.rs +++ b/src/runtimes/modules/native.rs @@ -1,7 +1,7 @@ // Copyright 2022 VMware, Inc. // SPDX-License-Identifier: Apache-2.0 -use crate::workers::runtime::Runtime; +use crate::runtimes::runtime::Runtime; use anyhow::Result; use std::{fs, path::PathBuf}; diff --git a/src/runtimes/remote_file.rs b/src/runtimes/remote_file.rs new file mode 100644 index 00000000..c14a7b14 --- /dev/null +++ b/src/runtimes/remote_file.rs @@ -0,0 +1,24 @@ +use serde::Deserialize; + +/// A file represents a combination of both a remote URL and +/// a checksum. It will provide utils to download and validate +/// the file. +/// +/// If the checksum is not present, the validation will return +/// always an Ok result. +/// +#[derive(Deserialize)] +pub struct RemoteFile<'a> { + /// URL pointing to the file + pub url: &'a str, + /// Checksum to validate the given file + pub checksum: Checksum<'a>, +} + +/// A list of available checksums. For now, +/// we will support only sha256 +#[derive(Deserialize)] +#[serde(rename_all = "lowercase", tag = "type")] +pub enum Checksum<'a> { + Sha256 { value: &'a str }, +} diff --git a/src/runtimes/repository.rs b/src/runtimes/repository.rs new file mode 100644 index 00000000..d19d0710 --- /dev/null +++ b/src/runtimes/repository.rs @@ -0,0 +1,49 @@ +// Copyright 2022 VMware, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use super::metadata::RuntimeMetadata; +use anyhow::{anyhow, Result}; +use serde::Deserialize; + +// TODO: Remove it when implementing the manager +#[allow(dead_code)] +/// A Repository contains the list of runtimes available on it. +/// This file is used by wws to properly show the list of available +/// repos and install them. +/// +/// By default, this repository class rely on the [WebAssembly Language Runtimes](https://github.com/vmware-labs/webassembly-language-runtimes) +/// repository. It looks for a repository.toml file in the Git repo. +#[derive(Deserialize)] +pub struct Repository<'a> { + /// Version of the repository file + pub version: u32, + /// The list of runtimes available in the repository + #[serde(borrow)] + pub runtimes: Vec>, +} + +// TODO: Remove it when implementing the manager +#[allow(dead_code)] +impl<'a> Repository<'a> { + /// Reads and parses the metadata from a slice of bytes. It will return + /// a result as the deserialization may fail. + pub fn from_slice(data: &'a [u8]) -> Result { + toml::from_slice::(data) + .map_err(|_| anyhow!("wws could not deserialize the repository metadata")) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + + #[test] + fn parse_index_toml() { + let contents = fs::read("tests/data/metadata/repository.toml").unwrap(); + let repo = Repository::from_slice(&contents).unwrap(); + + assert_eq!(repo.version, 1); + assert_eq!(repo.runtimes.len(), 1); + } +} diff --git a/src/workers/runtime.rs b/src/runtimes/runtime.rs similarity index 74% rename from src/workers/runtime.rs rename to src/runtimes/runtime.rs index ee4caf43..b9842cc6 100644 --- a/src/workers/runtime.rs +++ b/src/runtimes/runtime.rs @@ -1,11 +1,35 @@ // Copyright 2022 VMware, Inc. // SPDX-License-Identifier: Apache-2.0 -use super::runtimes::{javascript::JavaScriptRuntime, native::NativeRuntime}; +use super::modules::{javascript::JavaScriptRuntime, native::NativeRuntime}; use anyhow::{anyhow, Result}; +use serde::Deserialize; use std::path::Path; use wasmtime_wasi::WasiCtxBuilder; +/// Define the status of a runtime in a target repository +#[derive(Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum RuntimeStatus { + Active, + Yanked, + Deprecated, + Unknown, +} + +impl From<&str> for RuntimeStatus { + /// Create a RuntimeStatus variant from a &str. It uses predefined + /// values + fn from(value: &str) -> Self { + match value { + "active" => RuntimeStatus::Active, + "yanked" => RuntimeStatus::Yanked, + "deprecated" => RuntimeStatus::Deprecated, + _ => RuntimeStatus::Unknown, + } + } +} + /// Define the behavior a Runtime must have. This includes methods /// to initialize the environment for the given runtime as well as /// the Wasi Context to process the request. diff --git a/src/workers/mod.rs b/src/workers/mod.rs index 6292acd4..2d2f3216 100644 --- a/src/workers/mod.rs +++ b/src/workers/mod.rs @@ -1,8 +1,6 @@ // Copyright 2022 VMware, Inc. // SPDX-License-Identifier: Apache-2.0 -mod runtime; -mod runtimes; pub mod wasm_io; mod worker; diff --git a/src/workers/worker.rs b/src/workers/worker.rs index 7453e31c..980926ae 100644 --- a/src/workers/worker.rs +++ b/src/workers/worker.rs @@ -1,10 +1,8 @@ // Copyright 2022 VMware, Inc. // SPDX-License-Identifier: Apache-2.0 -use super::{ - runtime::{init_runtime, Runtime}, - wasm_io::{WasmInput, WasmOutput}, -}; +use super::wasm_io::{WasmInput, WasmOutput}; +use crate::runtimes::runtime::{init_runtime, Runtime}; use actix_web::HttpRequest; use anyhow::Result; use std::{collections::HashMap, path::Path}; diff --git a/tests/data/metadata/repository.toml b/tests/data/metadata/repository.toml new file mode 100644 index 00000000..a1ead61e --- /dev/null +++ b/tests/data/metadata/repository.toml @@ -0,0 +1,11 @@ +version = 1 + +[[runtimes]] +name = "ruby" +version = "3.2.0+20230118-8aec06d" +status = "active" +args = [ "--", "/src/index.rb" ] +binary = { url = "https://github.com/vmware-labs/webassembly-language-runtimes/releases/download/ruby%2F3.2.0%2B20230118-8aec06d/ruby-3.2.0.wasm", checksum = { type = "sha256", value = "e2d91cff05ec59ed9c88aadbd3b477842092054bf24c5d944d5ad6dbafdd3b32" } } +extensions = [ "rb" ] +polyfill = { url = "https://raw.githubusercontent.com/Angelmmiguel/wws-index-test/main/ruby/poly.rb", checksum = { type = "sha256", value = "2ba09117ed20a05480615b2aaaf6c7cd7f61fa06f4919777d773df2fcbc736cf" } } +template = { url = "https://raw.githubusercontent.com/Angelmmiguel/wws-index-test/main/ruby/template.txt", checksum = { type = "sha256", value = "6d808b4747cf30f82665a38a47e1176513bbdd6ad558c09db03d719e33ad2da0" } } \ No newline at end of file diff --git a/tests/data/metadata/runtime.toml b/tests/data/metadata/runtime.toml new file mode 100644 index 00000000..5e6c37f3 --- /dev/null +++ b/tests/data/metadata/runtime.toml @@ -0,0 +1,8 @@ +name = "ruby" +version = "3.2.0+20230118-8aec06d" +status = "active" +args = [ "--", "/src/index.rb" ] +binary = { url = "https://github.com/vmware-labs/webassembly-language-runtimes/releases/download/ruby%2F3.2.0%2B20230118-8aec06d/ruby-3.2.0.wasm", checksum = { type = "sha256", value = "e2d91cff05ec59ed9c88aadbd3b477842092054bf24c5d944d5ad6dbafdd3b32" } } +extensions = [ "rb" ] +polyfill = { url = "https://raw.githubusercontent.com/Angelmmiguel/wws-index-test/main/ruby/poly.rb", checksum = { type = "sha256", value = "2ba09117ed20a05480615b2aaaf6c7cd7f61fa06f4919777d773df2fcbc736cf" } } +template = { url = "https://raw.githubusercontent.com/Angelmmiguel/wws-index-test/main/ruby/template.txt", checksum = { type = "sha256", value = "6d808b4747cf30f82665a38a47e1176513bbdd6ad558c09db03d719e33ad2da0" } } \ No newline at end of file