Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add functions to create and publish packages and to deploy apps. #424

Merged
merged 32 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
9f69d51
feat: Update wasmer dependencies
xdoardo Jul 8, 2024
12b00b7
feat: Add registry API and tests
xdoardo Jul 8, 2024
21c8ff8
feat: Use same `Wasmer` type as output of created packages, update tests
xdoardo Jul 11, 2024
5d93785
chore: Formatting
xdoardo Jul 11, 2024
a16acfa
feat: Allow users to specify metadata in various formats
xdoardo Jul 23, 2024
9b256b2
Fix: use git repository to patch `webc`
xdoardo Jul 23, 2024
ff5db26
fix: Use spaces instead of tabs in the js part of the code
xdoardo Jul 24, 2024
29e26f4
feat: Add atoms to manifests and use latest revision of webc crate
xdoardo Jul 26, 2024
2b4211c
feat: Allow users to specify just their token while initializing the …
xdoardo Jul 31, 2024
fc39403
chore: Use spaces
xdoardo Jul 31, 2024
c3081da
fix: Add more tests and remove spurious tracing messages
xdoardo Aug 1, 2024
0fdd6ba
fix: use env variables in tests
xdoardo Aug 2, 2024
ec087eb
fix: address comments
xdoardo Aug 2, 2024
acaf046
chore: Update dependencies
xdoardo Aug 2, 2024
d634399
chore: Make linter happy
xdoardo Aug 2, 2024
4711513
chore: Use newly-released version of pirita
xdoardo Aug 2, 2024
e8a2210
chore: Move const initialisation out of test
xdoardo Aug 2, 2024
118e461
chore: Replace removed function from `ModuleHash`
xdoardo Aug 2, 2024
18eee39
chore: rollback rollup change
xdoardo Aug 2, 2024
2e4679a
Update ci.yml
xdoardo Aug 2, 2024
0b5eab9
fix: Use single input for initalization function
xdoardo Aug 5, 2024
26cfdc3
chore: Make linter happy
xdoardo Aug 5, 2024
c648829
chore: fix tests
xdoardo Aug 5, 2024
3a9019c
fix: remove typo
xdoardo Aug 5, 2024
591bdcb
fix: with -> assert
xdoardo Aug 5, 2024
f691359
chore: fix ci tests
xdoardo Aug 5, 2024
f0442e9
chore: fix ci docs
xdoardo Aug 5, 2024
29447c9
chore: add `.env` to .gitignore
xdoardo Aug 5, 2024
37d1326
chore: release 0.7.0-alpha
xdoardo Aug 5, 2024
e94ce1d
chore: release 0.7.0-alpha.1
xdoardo Aug 6, 2024
ad91eb5
chore: Update rollup and change type for entry function
xdoardo Aug 6, 2024
0464d61
fix: Use a global variable to signal which init function to use
xdoardo Aug 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,656 changes: 1,440 additions & 216 deletions Cargo.lock

Large diffs are not rendered by default.

26 changes: 17 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,28 @@ http = "0.2"
instant = { version = "0.1", features = ["wasm-bindgen"] }
js-sys = "0.3"
once_cell = "1"
reqwest = { version = "0.12.5", features = ["stream"] }
serde = { version = "1", features = ["derive"] }
serde-wasm-bindgen = "0.6"
sha2 = "0.10.8"
tempfile = "3.10.1"
tokio = { version = "1", features = ["sync"], default_features = false }
toml = "0.8.14"
tracing = { version = "0.1", features = ["log", "release_max_level_debug"] }
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
url = "2.4.0"
virtual-fs = { version = "0.11.0", default-features = false }
virtual-net = { version = "0.6.0", default-features = false, features = ["remote"] }
virtual-fs = { version = "0.13.0", default-features = false }
virtual-net = { version = "0.6.7", default-features = false, features = ["remote"] }
wasm-bindgen = { version = "0.2" }
wasm-bindgen-derive = "0.2.1"
wasm-bindgen-futures = "0.4"
wasm-bindgen-test = "0.3.37"
wasmer = { version = "4.2.5", default-features = false, features = ["js", "js-default", "tracing", "wasm-types-polyfill", "enable-serde"] }
wasmer-wasix = { version = "0.18", default-features = false, features = ["js", "js-default"] }
webc = "5.3.0"
wasmer = { version = "4.3.2", default-features = false, features = ["js", "js-default", "wasm-types-polyfill", "enable-serde"] }
wasmer-api = { version = "0.0.30", git = "https://github.com/wasmerio/wasmer", branch = "backend-api-wasm32"}
wasmer-config = "0.4.0"
wasmer-types = "4.3.2"
wasmer-wasix = { version = "0.22.0", default-features = false, features = ["js", "js-default"] }
webc = "6.0.0-rc1"

[dependencies.web-sys]
version = "0.3"
Expand Down Expand Up @@ -95,10 +102,11 @@ dwarf-debug-info = false
wasm-opt = ["--enable-threads", "--enable-bulk-memory", "-Oz"]

[patch.crates-io]
virtual-net = { git = "https://github.com/wasmerio/wasmer", branch = "master" }
virtual-fs = { git = "https://github.com/wasmerio/wasmer", branch = "master" }
wasmer-wasix = { git = "https://github.com/wasmerio/wasmer", branch = "master" }
wasmer = { git = "https://github.com/wasmerio/wasmer", branch = "master" }
webc = {git = "https://github.com/wasmerio/pirita", branch = "in-memory-manifest"}
#virtual-net = { git = "https://github.com/wasmerio/wasmer", branch = "master" }
#virtual-fs = { git = "https://github.com/wasmerio/wasmer", branch = "master" }
#wasmer-wasix = { git = "https://github.com/wasmerio/wasmer", branch = "master" }
#wasmer = { git = "https://github.com/wasmerio/wasmer", branch = "master" }
# virtual-net = { path = "../wasmer/lib/virtual-net" }
# virtual-fs = { path = "../wasmer/lib/virtual-fs" }
# wasmer-wasix = { path = "../wasmer/lib/wasix" }
Expand Down
49 changes: 33 additions & 16 deletions WasmerSDK.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,48 @@
export * from "./pkg/wasmer_js";
// @ts-ignore
import load, { InitInput, InitOutput, ThreadPoolWorker, setWorkerUrl } from "./pkg/wasmer_js";
import load, { InitInput, InitOutput, ThreadPoolWorker, setWorkerUrl, RegistryConfig } from "./pkg/wasmer_js";

type RegistryInput = {
registry_url: string,
token?: string
}

/**
* Initialize the underlying WebAssembly module.
*/
export const init = async (module_or_path?: InitInput | Promise<InitInput>, maybe_memory?: WebAssembly.Memory): Promise<InitOutput> => {
if (!module_or_path) {
// This will be replaced by the rollup bundler at the SDK build time
// to point to a valid http location of the SDK using unpkg.com.
let wasmUrl = (globalThis as any)["wasmUrl"];
if (wasmUrl) {
module_or_path = new URL(wasmUrl);
}
export const init = async (module_or_path?: InitInput | Promise<InitInput>, maybe_memory?: WebAssembly.Memory, maybe_registry?: string | RegistryInput): Promise<InitOutput> => {
if (!module_or_path) {
// This will be replaced by the rollup bundler at the SDK build time
// to point to a valid http location of the SDK using unpkg.com.
let wasmUrl = (globalThis as any)["wasmUrl"];
if (wasmUrl) {
module_or_path = new URL(wasmUrl);
}
}

const DEFAULT_REGISTRY = "https://registry.wasmer.io/graphql";

if (typeof maybe_registry === 'string' || maybe_registry instanceof String) {
(globalThis as any)["__WASMER_REGISTRY__"] = {
"registry": DEFAULT_REGISTRY,
"token": maybe_registry
};
} else {
(globalThis as any)["__WASMER_REGISTRY__"] = maybe_registry;
}
return load(module_or_path, maybe_memory);

return load(module_or_path, maybe_memory);
}

/**
* Set a deafult working Worker Url. Which in this case will be
* an unpkg url that is set up at the SDK build time.
*/
export const setDefaultWorkerUrl = () => {
let workerUrl = (globalThis as any)["workerUrl"];
if (workerUrl) {
setWorkerUrl(workerUrl)
}
let workerUrl = (globalThis as any)["workerUrl"];
if (workerUrl) {
setWorkerUrl(workerUrl)
}
xdoardo marked this conversation as resolved.
Show resolved Hide resolved
}

// HACK: We save these to the global scope because it's the most reliable way to
Expand All @@ -35,5 +52,5 @@ export const setDefaultWorkerUrl = () => {

// HACK: some bundlers such as webpack uses this on dev mode.
// We add this functions to allow dev mode work in those bundlers.
(globalThis as any).$RefreshReg$ = (globalThis as any).$RefreshReg$ || function () {/**/ };
(globalThis as any).$RefreshSig$ = (globalThis as any).$RefreshSig$ || function () { return function () { } };
(globalThis as any).$RefreshReg$ = (globalThis as any).$RefreshReg$ || function() {/**/ };
(globalThis as any).$RefreshSig$ = (globalThis as any).$RefreshSig$ || function() { return function() { } };
2 changes: 1 addition & 1 deletion rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import terser from "@rollup/plugin-terser";
import pkg from "./package.json" assert { type: "json" };
import pkg from "./package.json" with { type: "json" };
import dts from "rollup-plugin-dts";
import typescript from "@rollup/plugin-typescript";
import replace from "@rollup/plugin-replace";
Expand Down
10 changes: 10 additions & 0 deletions src/fs/directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,16 @@ impl FileSystem for Directory {
fn new_open_options(&self) -> virtual_fs::OpenOptions {
virtual_fs::OpenOptions::new(self)
}

#[tracing::instrument(level = "trace", skip(self))]
fn readlink(&self, path: &Path) -> virtual_fs::Result<PathBuf> {
self.0.readlink(path)
}

#[tracing::instrument(level = "trace", skip(self))]
fn symlink_metadata(&self, path: &Path) -> virtual_fs::Result<virtual_fs::Metadata> {
self.0.symlink_metadata(path)
}
}

impl virtual_fs::FileOpener for Directory {
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![feature(once_cell_try)]

#[cfg(test)]
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);

Expand All @@ -10,6 +12,7 @@ mod logging;
mod net;
mod options;
mod package_loader;
pub mod registry;
mod run;
mod runtime;
mod streams;
Expand Down
3 changes: 1 addition & 2 deletions src/package_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ impl wasmer_wasix::runtime::package_loader::PackageLoader for PackageLoader {
#[tracing::instrument(
skip_all,
fields(
pkg.name=summary.pkg.name.as_str(),
pkg.version=%summary.pkg.version,
pkg=format!("{:?}", summary.pkg.id),
pkg.url=summary.dist.webc.as_str(),
),
)]
Expand Down
117 changes: 117 additions & 0 deletions src/registry/app.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
use wasmer_api::types::{DeployAppVersion, PublishDeployAppVars};
use wasmer_config::app::AppConfigV1;

use crate::{
utils::{self, Error},
Wasmer,
};

#[wasm_bindgen(getter_with_clone)]
#[derive(Debug, Clone)]
pub struct DeployedApp {
pub id: String,
pub created_at: String,
pub version: String,
pub description: Option<String>,
pub yaml_config: String,
pub user_yaml_config: String,
pub config: String,
pub json_config: String,
pub url: String,
}

impl From<DeployAppVersion> for DeployedApp {
fn from(value: DeployAppVersion) -> Self {
Self {
id: value.id.inner().to_string(),
created_at: value.created_at.0,
version: value.version,
description: value.description,
yaml_config: value.yaml_config,
user_yaml_config: value.user_yaml_config,
config: value.config,
json_config: value.json_config,
url: value.url,
}
}
}

fn resolve_pkg(app_config: &JsValue) -> anyhow::Result<()> {
// The app config must have a 'package' field.
//
// The package field can either be a raw string or a [`Wasmer`].

let package_key = JsValue::from_str("package");
let package = js_sys::Reflect::get(app_config, &package_key).map_err(|e| {
anyhow::anyhow!("While trying to get the package field from the app config: {e:?}")
})?;

if package.is_undefined() {
anyhow::bail!(
"While trying to get the package field from the app config: undefined field name"
)
}

let pkg_key = JsValue::from_str("pkg");

if package.is_string() {
// Do nothing
Ok(())
} else if js_sys::Reflect::has(&package, &pkg_key).map_err(|e| anyhow::anyhow!("{e:?}"))? {
let pkg = js_sys::Reflect::get(&package, &pkg_key).unwrap();
let hash_key = JsValue::from_str("hash");
if js_sys::Reflect::has(&pkg, &hash_key).map_err(|e| anyhow::anyhow!("{e:?}"))? {
let hash = js_sys::Reflect::get(&pkg, &hash_key).unwrap();
js_sys::Reflect::set(app_config, &package_key, &hash)
.map_err(|e| anyhow::anyhow!("{e:?}"))?;

Ok(())
} else {
anyhow::bail!("No package information provided! Set the 'package'")
}
} else {
anyhow::bail!("No package information provided! Set the 'package'")
}
}

#[wasm_bindgen]
impl Wasmer {
/// Deploy an app to the registry.
#[wasm_bindgen(js_name = "deployApp")]
#[allow(non_snake_case)]
pub async fn deploy_app(appConfig: JsValue) -> Result<DeployedApp, Error> {
resolve_pkg(&appConfig)?;

let default = js_sys::Reflect::get(&appConfig, &(String::from("default").into()))
.map_err(utils::js_error)?
.as_bool();
let app_config = serde_wasm_bindgen::from_value(appConfig)
.map_err(|e| anyhow::anyhow!("{e:?}"))?;

Wasmer::deploy_app_inner(app_config, default).await
}
}

impl Wasmer {
async fn deploy_app_inner(
app_config: AppConfigV1,
make_default: Option<bool>,
) -> Result<DeployedApp, Error> {
let client = Wasmer::get_client()?;
let config = app_config.clone().to_yaml()?;

wasmer_api::query::publish_deploy_app(
client,
PublishDeployAppVars {
config,
name: app_config.name.into(),
owner: app_config.owner.map(Into::into),
make_default,
},
)
.await
.map(|v| v.into())
.map_err(|e| utils::Error::Rust(anyhow::anyhow!("{e:?}")))
}
}
73 changes: 73 additions & 0 deletions src/registry/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
pub mod app;
pub mod package;

use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
use wasmer_api::WasmerClient;

use crate::{utils::Error, Wasmer};

static WASMER_CLIENT: std::sync::OnceLock<WasmerClient> = std::sync::OnceLock::new();

#[wasm_bindgen(getter_with_clone)]
pub struct RegistryConfig {
pub registry_url: String,
xdoardo marked this conversation as resolved.
Show resolved Hide resolved
pub token: Option<String>,
}

impl Default for RegistryConfig {
fn default() -> Self {
Self {
registry_url: String::from("https://registry.wasmer.io/graphql"),
xdoardo marked this conversation as resolved.
Show resolved Hide resolved
token: Default::default(),
}
}
}

impl Wasmer {
pub fn get_client() -> Result<&'static WasmerClient, Error> {
WASMER_CLIENT.get_or_try_init(|| {
let registry_input = if let Some(registry_info) =
web_sys::window().and_then(|w| w.get("__WASMER_REGISTRY__"))
{
if registry_info.is_undefined() {
RegistryConfig::default()
} else {
let registry_url = js_sys::Reflect::get(
&registry_info,
&JsValue::from(String::from("registry_url")),
)
.ok()
.and_then(|u| u.as_string());
let token =
js_sys::Reflect::get(&registry_info, &JsValue::from(String::from("token")))
.ok()
.and_then(|u| u.as_string());

if let Some(registry_url) = registry_url {
RegistryConfig {
registry_url,
token,
}
} else {
RegistryConfig {
token,
..Default::default()
}
}
}
} else {
RegistryConfig::default()
};

let mut client = wasmer_api::WasmerClient::new(
url::Url::parse(&registry_input.registry_url)?,
xdoardo marked this conversation as resolved.
Show resolved Hide resolved
"Wasmer JS SDK",
)?;
if let Some(token) = registry_input.token {
client = client.with_auth_token(token);
}

Ok(client)
})
}
}
Loading
Loading