From acab656dd9570850966a768e4a6d7ba8316dfd26 Mon Sep 17 00:00:00 2001 From: Dima Date: Fri, 11 Sep 2020 15:58:38 +0300 Subject: [PATCH] site-storage wasm project (#25) --- Cargo.lock | 115 +++++++++++------- Cargo.toml | 3 + README.md | 33 +++-- examples/site-storage/Config.toml | 21 ++++ examples/site-storage/build.sh | 18 +++ .../wasm/artifacts/modules/site-storage.wasm | Bin 0 -> 85065 bytes examples/site-storage/wasm/curl/Cargo.toml | 13 ++ examples/site-storage/wasm/curl/src/main.rs | 37 ++++++ .../wasm/local_storage/Cargo.toml | 13 ++ .../wasm/local_storage/src/main.rs | 51 ++++++++ .../site-storage/wasm/site-storage/Cargo.toml | 14 +++ .../wasm/site-storage/src/main.rs | 53 ++++++++ 12 files changed, 315 insertions(+), 56 deletions(-) create mode 100644 examples/site-storage/Config.toml create mode 100755 examples/site-storage/build.sh create mode 100755 examples/site-storage/wasm/artifacts/modules/site-storage.wasm create mode 100644 examples/site-storage/wasm/curl/Cargo.toml create mode 100644 examples/site-storage/wasm/curl/src/main.rs create mode 100644 examples/site-storage/wasm/local_storage/Cargo.toml create mode 100644 examples/site-storage/wasm/local_storage/src/main.rs create mode 100644 examples/site-storage/wasm/site-storage/Cargo.toml create mode 100644 examples/site-storage/wasm/site-storage/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 3b1b6b6c..7d249ba5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -356,6 +356,14 @@ dependencies = [ "syn", ] +[[package]] +name = "curl" +version = "0.1.0" +dependencies = [ + "fluence", + "log", +] + [[package]] name = "darling" version = "0.10.2" @@ -644,7 +652,7 @@ dependencies = [ [[package]] name = "fluence" version = "0.2.2" -source = "git+https://github.com/fluencelabs/rust-sdk#ff447a32586b3f088a57fe51b1e5baf3e17b5c12" +source = "git+https://github.com/fluencelabs/rust-sdk#dcb6cfddf95978e777a8a53710bda88aec7d4baf" dependencies = [ "fluence-sdk-macro 0.2.2 (git+https://github.com/fluencelabs/rust-sdk)", "fluence-sdk-main 0.2.2 (git+https://github.com/fluencelabs/rust-sdk)", @@ -680,14 +688,6 @@ dependencies = [ "wasmer-wasi-fl", ] -[[package]] -name = "fluence-sdk-macro" -version = "0.2.2" -source = "git+https://github.com/fluencelabs/rust-sdk#ff447a32586b3f088a57fe51b1e5baf3e17b5c12" -dependencies = [ - "fluence-sdk-wit 0.2.2 (git+https://github.com/fluencelabs/rust-sdk)", -] - [[package]] name = "fluence-sdk-macro" version = "0.2.2" @@ -698,13 +698,11 @@ dependencies = [ ] [[package]] -name = "fluence-sdk-main" +name = "fluence-sdk-macro" version = "0.2.2" -source = "git+https://github.com/fluencelabs/rust-sdk#ff447a32586b3f088a57fe51b1e5baf3e17b5c12" +source = "git+https://github.com/fluencelabs/rust-sdk#dcb6cfddf95978e777a8a53710bda88aec7d4baf" dependencies = [ - "fluence-sdk-macro 0.2.2 (git+https://github.com/fluencelabs/rust-sdk)", - "log", - "serde", + "fluence-sdk-wit 0.2.2 (git+https://github.com/fluencelabs/rust-sdk)", ] [[package]] @@ -718,10 +716,21 @@ dependencies = [ "serde", ] +[[package]] +name = "fluence-sdk-main" +version = "0.2.2" +source = "git+https://github.com/fluencelabs/rust-sdk#dcb6cfddf95978e777a8a53710bda88aec7d4baf" +dependencies = [ + "fluence-sdk-macro 0.2.2 (git+https://github.com/fluencelabs/rust-sdk)", + "log", + "serde", +] + [[package]] name = "fluence-sdk-wit" version = "0.2.2" -source = "git+https://github.com/fluencelabs/rust-sdk#ff447a32586b3f088a57fe51b1e5baf3e17b5c12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93c94643121eb234778b7f8f0e12fd29ec7c70ac71d84329ae25daf5d263074d" dependencies = [ "proc-macro2", "quote", @@ -734,8 +743,7 @@ dependencies = [ [[package]] name = "fluence-sdk-wit" version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c94643121eb234778b7f8f0e12fd29ec7c70ac71d84329ae25daf5d263074d" +source = "git+https://github.com/fluencelabs/rust-sdk#dcb6cfddf95978e777a8a53710bda88aec7d4baf" dependencies = [ "proc-macro2", "quote", @@ -884,9 +892,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", @@ -1146,9 +1154,9 @@ checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "js-sys" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a7e2c92a4804dd459b86c339278d0fe87cf93757fae222c3fa3ae75458bc73" +checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8" dependencies = [ "wasm-bindgen", ] @@ -1190,9 +1198,17 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.76" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" + +[[package]] +name = "local_storage" +version = "0.1.0" +dependencies = [ + "fluence", + "log", +] [[package]] name = "lock_api" @@ -1559,9 +1575,9 @@ checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" [[package]] name = "proc-macro2" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175c513d55719db99da20232b06cda8bab6b83ec2d04e3283edf0213c37c1a29" +checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" dependencies = [ "unicode-xid", ] @@ -1961,6 +1977,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +[[package]] +name = "site-storage" +version = "0.1.0" +dependencies = [ + "anyhow", + "fluence", + "log", +] + [[package]] name = "skim" version = "0.7.0" @@ -2000,9 +2025,9 @@ checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" [[package]] name = "socket2" -version = "0.3.12" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44" dependencies = [ "cfg-if", "libc", @@ -2030,9 +2055,9 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" [[package]] name = "subtle" -version = "2.2.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502d53007c02d7605a05df1c1a73ee436952781653da5d0bf57ad608f66932c1" +checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd" [[package]] name = "syn" @@ -2249,9 +2274,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f0e00789804e99b20f12bc7003ca416309d28a6f495d6af58d1e2c2842461b5" +checksum = "5bcf46c1f1f06aeea2d6b81f3c863d0930a596c86ad1920d4e5bad6dd1d7119a" dependencies = [ "lazy_static", ] @@ -2466,9 +2491,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c" +checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" dependencies = [ "cfg-if", "serde", @@ -2478,9 +2503,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0" +checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68" dependencies = [ "bumpalo", "lazy_static", @@ -2493,9 +2518,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.17" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95f8d235a77f880bcef268d379810ea6c0af2eacfa90b1ad5af731776e0c4699" +checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da" dependencies = [ "cfg-if", "js-sys", @@ -2505,9 +2530,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2" +checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2515,9 +2540,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556" +checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" dependencies = [ "proc-macro2", "quote", @@ -2528,9 +2553,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092" +checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" [[package]] name = "wasm-greeting" @@ -2731,9 +2756,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda38f4e5ca63eda02c059d243aa25b5f35ab98451e518c51612cd0f1bd19a47" +checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 6cac8ed0..a2856ee7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,9 @@ members = [ "examples/records/effector", "examples/records/pure", "examples/records/test-record", + "examples/site-storage/wasm/site-storage", + "examples/site-storage/wasm/curl", + "examples/site-storage/wasm/local_storage", "fluence-app-service", "fluence-faas", "tools/cli", diff --git a/README.md b/README.md index c5fb9d7f..3a8a8fb9 100644 --- a/README.md +++ b/README.md @@ -46,19 +46,19 @@ pub fn get(url: String) -> String { - Build project with `fce build` (supports --release and all other cargo flags now) -- Copy wasm file from `target/wasm32-wasi/debug` to directory with other modules +- Copy wasm file from `target/wasm32-wasi/debug` or `target/wasm32-wasi/release` to directory with other modules - To import other wasm modules to your project use similar code: ```rust #[fce] -#[link(wasm_import_module = "wasm_curl.wasm")] +#[link(wasm_import_module = "curl")] extern "C" { #[link_name = "get"] pub fn curl_get(url: String) -> String; } #[fce] -#[link(wasm_import_module = "wasm_local_storage.wasm")] +#[link(wasm_import_module = "local_storage")] extern "C" { #[link_name = "get"] pub fn curl_get(url: String) -> String; @@ -70,19 +70,29 @@ extern "C" { - Create simple Rust project - Create `Config.toml` to describe existed wasm modules and give accesses to host binaries and local storage if needed: ```toml -modules_dir = "wasm/artifacts/modules" +modules_dir = "wasm/artifacts/modules/" [[module]] - name = "wasm_local_storage_with_curl.wasm" - mem_pages_count = 100 - - [module.imports] - curl = "/usr/bin/curl" + name = "local_storage" + logger_enabled = true [module.wasi] - envs = [] preopened_files = ["./wasm/artifacts"] - mapped_dirs = { "tmp" = "./wasm/artifacts" } + mapped_dirs = { "sites" = "./sites" } + +[[module]] + name = "curl" + logger_enabled = true + + [module.imports] + curl = "/usr/bin/curl" + +[[module]] + name = "site-storage" + mem_pages_count = 10000 + logger_enabled = true + [module.wasi] + envs = ["ENV_ONE=parameter-one"] ``` `modules_dir` - path to directory with all modules. All subsequent paths will be relative to this path @@ -99,6 +109,7 @@ modules_dir = "wasm/artifacts/modules" Import example: ```rust +#[fce] #[link(wasm_import_module = "host")] extern "C" { fn curl(args: String) -> String; diff --git a/examples/site-storage/Config.toml b/examples/site-storage/Config.toml new file mode 100644 index 00000000..ed6c15b2 --- /dev/null +++ b/examples/site-storage/Config.toml @@ -0,0 +1,21 @@ +modules_dir = "wasm/artifacts/modules/" + +[[module]] + name = "local_storage" + logger_enabled = true + + [module.wasi] + preopened_files = ["./../sites"] + # this is where files will be stored + mapped_dirs = { "sites" = "./../sites" } + +[[module]] + name = "curl" + logger_enabled = true + + [module.imports] + curl = "/usr/bin/curl" + +[[module]] + name = "site-storage" + logger_enabled = true diff --git a/examples/site-storage/build.sh b/examples/site-storage/build.sh new file mode 100755 index 00000000..81ecf1d2 --- /dev/null +++ b/examples/site-storage/build.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +# This script builds all subprojects and puts all created Wasm modules in one dir +cd wasm/site-storage +cargo update +fce build --release +cd ../curl +cargo update +fce build --release +cd ../local_storage +cargo update +fce build --release + +cd .. +rm artifacts/modules/* +cp ../../../target/wasm32-wasi/release/curl.wasm artifacts/modules +cp ../../../target/wasm32-wasi/release/local_storage.wasm artifacts/modules +cp ../../../target/wasm32-wasi/release/site-storage.wasm artifacts/modules diff --git a/examples/site-storage/wasm/artifacts/modules/site-storage.wasm b/examples/site-storage/wasm/artifacts/modules/site-storage.wasm new file mode 100755 index 0000000000000000000000000000000000000000..b954f04f4a0f1c7817a36e9af3acbcaf8a8557c0 GIT binary patch literal 85065 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 Pve`m@S#ibkRm1-ujnQ>Y literal 0 HcmV?d00001 diff --git a/examples/site-storage/wasm/curl/Cargo.toml b/examples/site-storage/wasm/curl/Cargo.toml new file mode 100644 index 00000000..6a951b9c --- /dev/null +++ b/examples/site-storage/wasm/curl/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "curl" +version = "0.1.0" +authors = ["Fluence Labs"] +edition = "2018" + +[[bin]] +path = "src/main.rs" +name = "curl" + +[dependencies] +fluence = { git = "https://github.com/fluencelabs/rust-sdk", features = ["logger"] } +log = "0.4.8" diff --git a/examples/site-storage/wasm/curl/src/main.rs b/examples/site-storage/wasm/curl/src/main.rs new file mode 100644 index 00000000..c392645c --- /dev/null +++ b/examples/site-storage/wasm/curl/src/main.rs @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use fluence::fce; +use fluence::WasmLogger; + +/// Log level can be changed by `RUST_LOG` env as well. +pub fn main() { + WasmLogger::init_with_level(log::Level::Info).unwrap(); +} + +#[fce] +pub fn get(cmd: String) -> String { + log::info!("get called with url {}", cmd); + + unsafe { curl(cmd) } +} + +/// Permissions in `Config.toml` should exist to use host functions. +#[fce] +#[link(wasm_import_module = "host")] +extern "C" { + fn curl(cmd: String) -> String; +} diff --git a/examples/site-storage/wasm/local_storage/Cargo.toml b/examples/site-storage/wasm/local_storage/Cargo.toml new file mode 100644 index 00000000..8c04809e --- /dev/null +++ b/examples/site-storage/wasm/local_storage/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "local_storage" +version = "0.1.0" +authors = ["Fluence Labs"] +edition = "2018" + +[[bin]] +name = "local_storage" +path = "src/main.rs" + +[dependencies] +fluence = { git = "https://github.com/fluencelabs/rust-sdk", features = ["logger"] } +log = "0.4.8" diff --git a/examples/site-storage/wasm/local_storage/src/main.rs b/examples/site-storage/wasm/local_storage/src/main.rs new file mode 100644 index 00000000..1dfe1266 --- /dev/null +++ b/examples/site-storage/wasm/local_storage/src/main.rs @@ -0,0 +1,51 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::fs; +use fluence::fce; +use fluence::WasmLogger; +use std::path::PathBuf; + +const RPC_TMP_FILEPATH: &str = "/sites/"; + +/// Log level can be changed by `RUST_LOG` env as well. +pub fn main() { + WasmLogger::init_with_level(log::Level::Info).unwrap(); +} + +/// You can read or write files from the file system if there is permission to use directories described in `Config.toml`. +#[fce] +pub fn put(name: String, file_content: Vec) -> String { + log::info!("put called with {:?}", file_content); + + let rpc_tmp_filepath = format!("{}{}", RPC_TMP_FILEPATH, name); + + let result = fs::write(PathBuf::from(rpc_tmp_filepath.clone()), file_content); + if let Err(e) = result { + return format!("file can't be written: {}", e); + } + + return "Ok".to_string(); +} + +#[fce] +pub fn get(file_name: String) -> Vec { + log::info!("get called with file name: {}", file_name); + + let tmp_filepath = format!("{}{}", RPC_TMP_FILEPATH, file_name); + + fs::read(tmp_filepath).unwrap_or_else(|_| b"error while reading file".to_vec()) +} diff --git a/examples/site-storage/wasm/site-storage/Cargo.toml b/examples/site-storage/wasm/site-storage/Cargo.toml new file mode 100644 index 00000000..dea8018a --- /dev/null +++ b/examples/site-storage/wasm/site-storage/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "site-storage" +version = "0.1.0" +authors = ["Fluence Labs"] +edition = "2018" + +[[bin]] +name = "site-storage" +path = "src/main.rs" + +[dependencies] +fluence = { git = "https://github.com/fluencelabs/rust-sdk", features = ["logger"] } +anyhow = "1.0.31" +log = "0.4.8" diff --git a/examples/site-storage/wasm/site-storage/src/main.rs b/examples/site-storage/wasm/site-storage/src/main.rs new file mode 100644 index 00000000..ebad3f33 --- /dev/null +++ b/examples/site-storage/wasm/site-storage/src/main.rs @@ -0,0 +1,53 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use fluence::fce; +use fluence::WasmLogger; + +pub fn main() { + WasmLogger::init_with_level(log::Level::Info).unwrap(); +} + +/// Combining of modules: `curl` and `local_storage`. +/// Calls `curl` and stores returned result into a file. +#[fce] +fn get_n_save(url: String, file_name: String) -> String { + let result = unsafe { curl(url) }; + println!("execution result {:?}", result); + let a = unsafe { file_put(file_name, result.into_bytes()) }; + println!("{}", a); + + "Ok".to_string() +} + +/// Importing `curl` module +#[fce] +#[link(wasm_import_module = "curl")] +extern "C" { + #[link_name = "get"] + pub fn curl(url: String) -> String; +} + +/// Importing `local_storage` module +#[fce] +#[link(wasm_import_module = "local_storage")] +extern "C" { + #[link_name = "get"] + pub fn file_get(file_name: String) -> Vec; + + #[link_name = "put"] + pub fn file_put(name: String, file_content: Vec) -> String; +}