diff --git a/Cargo.lock b/Cargo.lock index 5dc7750c..91b02054 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -514,9 +514,20 @@ name = "ipfs_node" version = "0.1.0" dependencies = [ "fce", + "serde", + "serde_derive", + "serde_json", "toml", + "wasmer-runtime", + "wasmer-runtime-core", ] +[[package]] +name = "itoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" + [[package]] name = "lazy_static" version = "1.4.0" @@ -806,9 +817,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" +checksum = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d" dependencies = [ "serde_derive", ] @@ -834,15 +845,26 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" +checksum = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "serde_json" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "smallvec" version = "1.4.0" diff --git a/bin/wit_embedder b/bin/wit_embedder new file mode 100755 index 00000000..52f3b197 Binary files /dev/null and b/bin/wit_embedder differ diff --git a/crates/fce_wit_interfaces/src/fce_wit_interfaces.rs b/crates/fce_wit_interfaces/src/fce_wit_interfaces.rs index ea46ac85..b325dab1 100644 --- a/crates/fce_wit_interfaces/src/fce_wit_interfaces.rs +++ b/crates/fce_wit_interfaces/src/fce_wit_interfaces.rs @@ -35,13 +35,13 @@ pub struct FCEWITInterfaces<'a> { types: Vec, /// All the imported functions. - imports: HashMap, ImportNamespace<'a>)>, + imports: MultiMap, ImportNamespace<'a>)>, /// All the adapters. adapters: HashMap>, /// All the exported functions. - exports: HashMap>, + exports: MultiMap>, /// All the implementations. adapter_type_to_core: MultiMap, @@ -54,7 +54,7 @@ impl<'a> FCEWITInterfaces<'a> { .imports .into_iter() .map(|import| (import.function_type, (import.namespace, import.name))) - .collect::>(); + .collect::>(); let adapters = interfaces .adapters @@ -66,7 +66,7 @@ impl<'a> FCEWITInterfaces<'a> { .exports .into_iter() .map(|export| (export.function_type, export.name)) - .collect::>(); + .collect::>(); let adapter_type_to_core = interfaces .implementations @@ -120,19 +120,19 @@ impl<'a> FCEWITInterfaces<'a> { self.imports.iter() } - pub fn import_by_type( + pub fn imports_by_type( &self, import_type: CoreFunctionType, - ) -> Option<&(ImportName<'a>, ImportNamespace<'a>)> { - self.imports.get(&import_type) + ) -> Option<&Vec<(ImportName<'a>, ImportNamespace<'a>)>> { + self.imports.get_vec(&import_type) } - pub fn import_by_type_r( + pub fn imports_by_type_r( &self, import_type: CoreFunctionType, - ) -> Result<&(ImportName<'a>, ImportNamespace<'a>), FCEWITInterfacesError> { + ) -> Result<&Vec<(ImportName<'a>, ImportNamespace<'a>)>, FCEWITInterfacesError> { self.imports - .get(&import_type) + .get_vec(&import_type) .ok_or_else(|| FCEWITInterfacesError::NoSuchImport(import_type)) } @@ -153,14 +153,23 @@ impl<'a> FCEWITInterfaces<'a> { .ok_or_else(|| FCEWITInterfacesError::NoSuchAdapter(adapter_type)) } - pub fn export_by_type(&self, export_type: u32) -> Option<&ExportName<'a>> { - self.exports.get(&export_type) - } - pub fn exports(&self) -> impl Iterator)> { self.exports.iter() } + pub fn exports_by_type(&self, export_type: u32) -> Option<&Vec>> { + self.exports.get_vec(&export_type) + } + + pub fn exports_by_type_r( + &self, + export_type: CoreFunctionType, + ) -> Result<&Vec>, FCEWITInterfacesError> { + self.exports + .get_vec(&export_type) + .ok_or_else(|| FCEWITInterfacesError::NoSuchImport(export_type)) + } + pub fn implementations( &self, ) -> impl Iterator { diff --git a/examples/ipfs_node/Cargo.toml b/examples/ipfs_node/Cargo.toml index 77a626d1..18b7c289 100644 --- a/examples/ipfs_node/Cargo.toml +++ b/examples/ipfs_node/Cargo.toml @@ -6,4 +6,11 @@ edition = "2018" [dependencies] fce = { path = "../../fce" } + +wasmer-core = { package = "wasmer-runtime-core", version = "0.17.0" } +wasmer-runtime = "0.17.0" + toml = "0.5.6" +serde = { version = "1.0.111", features = ["derive"] } +serde_json = "1.0.53" +serde_derive = "1.0.111" diff --git a/examples/ipfs_node/Config.toml b/examples/ipfs_node/Config.toml index 9a44af68..1c4b5fad 100644 --- a/examples/ipfs_node/Config.toml +++ b/examples/ipfs_node/Config.toml @@ -1,6 +1,17 @@ -[ipfs_node] - [imports] +[[core_module]] + name = "ipfs_node.wasm" + mem_pages_count = 100 + logger_enabled = true + + [core_module.imports] + mysql = "/usr/bin/mysql" ipfs = "/usr/bin/ipfs" - [wasi] - preopened_dirs = ["/tmp"] + [core_module.wasi] + envs = ["asdsad=sdaasd"] + preopened_files = ["/tmp/file1"] + mapped_dirs = { tmp = "/tmp", tmp2 = "/tmp" } + +[rpc_module] + mem_pages_count = 100 + logger_enabled = true diff --git a/examples/ipfs_node/src/config.rs b/examples/ipfs_node/src/config.rs new file mode 100644 index 00000000..27bcc4be --- /dev/null +++ b/examples/ipfs_node/src/config.rs @@ -0,0 +1,175 @@ +/* + * 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 crate::errors::NodeError; + +use serde_derive::Deserialize; +use toml::from_slice; + +use std::collections::HashMap; + +/* +An example of a config: + +[ipfs_node] + mem_pages_count_count = 100 + logger_enabled = true + + [imports] + ipfs = "/usr/bin/ipfs" + mysql = "/usr/bin/mysql" + + [wasi] + preopened_files = ["/tmp/file1"] + [mapped_dirs] + tmp = "/tmp" + */ + +#[derive(Deserialize, Debug)] +pub(crate) struct RawCoreModulesConfig { + pub core_module: Vec, + pub rpc_module: Option, +} + +#[derive(Deserialize, Debug)] +pub(crate) struct RawModuleConfig { + pub name: String, + pub mem_pages_count: Option, + pub logger_enabled: Option, + pub imports: Option, + pub wasi: Option, +} + +#[derive(Deserialize, Debug)] +pub(crate) struct RawWASIConfig { + pub envs: Option>, + pub preopened_files: Option>, + pub mapped_dirs: Option, +} + +#[derive(Deserialize, Debug)] +pub(crate) struct RawRPCModuleConfig { + pub mem_pages_count: Option, + pub logger_enabled: Option, + pub wasi: Option, +} + +#[derive(Debug)] +pub(crate) struct NodeConfig { + pub modules_config: HashMap, + pub rpc_module_config: Option, +} + +#[derive(Debug)] +pub(crate) struct ModuleConfig { + pub mem_pages_count: Option, + pub logger_enabled: Option, + pub imports: Option>, + pub wasi: Option, +} + +#[derive(Debug)] +pub(crate) struct WASIConfig { + pub envs: Option>>, + pub preopened_files: Option>, + pub mapped_dirs: Option>, +} + +pub(crate) fn parse_config_from_file( + config_file_path: std::path::PathBuf, +) -> Result { + let file_content = std::fs::read(config_file_path)?; + let config: RawCoreModulesConfig = + from_slice(&file_content).map_err(|err| NodeError::ConfigParseError(format!("{}", err)))?; + + let modules_config = config + .core_module + .into_iter() + .map(|module| { + let imports: Option> = module.imports.map(|import| { + import + .into_iter() + .map(|(import_func_name, host_cmd)| { + (import_func_name, host_cmd.try_into::().unwrap()) + }) + .collect::>() + }); + + let wasi = module.wasi.map(|wasi| { + let envs = wasi + .envs + .map(|env| env.into_iter().map(|e| e.into_bytes()).collect::>()); + + let mapped_dirs = wasi.mapped_dirs.map(|mapped_dir| { + mapped_dir + .into_iter() + .map(|(from, to)| (from, to.try_into::().unwrap())) + .collect::>() + }); + WASIConfig { + envs, + preopened_files: wasi.preopened_files, + mapped_dirs, + } + }); + ( + module.name, + ModuleConfig { + mem_pages_count: module.mem_pages_count, + logger_enabled: module.logger_enabled, + imports, + wasi, + }, + ) + }) + .collect::>(); + + let rpc_module_config = config.rpc_module.map(|rpc_module| { + let wasi = rpc_module.wasi.map(|wasi| { + let envs = wasi + .envs + .map(|env| env.into_iter().map(|e| e.into_bytes()).collect::>()); + + let mapped_dirs = wasi.mapped_dirs.map(|mapped_dir| { + mapped_dir + .into_iter() + .map(|(from, to)| (from, to.try_into::().unwrap())) + .collect::>() + }); + WASIConfig { + envs, + preopened_files: wasi.preopened_files, + mapped_dirs, + } + }); + ModuleConfig { + mem_pages_count: rpc_module.mem_pages_count, + logger_enabled: rpc_module.logger_enabled, + imports: None, + wasi, + } + }); + + println!( + "parsed modules config:\n{:?}\nparsed rpc config:\n{:?}", + modules_config, rpc_module_config + ); + + Ok(NodeConfig { + modules_config, + rpc_module_config, + }) +} diff --git a/examples/ipfs_node/src/errors.rs b/examples/ipfs_node/src/errors.rs index 53b8445d..8b14db9c 100644 --- a/examples/ipfs_node/src/errors.rs +++ b/examples/ipfs_node/src/errors.rs @@ -16,13 +16,16 @@ use fce::FCEError; -use std::io::{Error as IOError, IoSliceMut}; +use std::io::Error as IOError; use std::error::Error; #[derive(Debug)] pub enum NodeError { + /// An error related to config parsing. + ConfigParseError(String), + /// Various errors related to file io. - IOError(IOError), + IOError(String), /// WIT doesn't contain such type. WasmProcessError(FCEError), @@ -33,7 +36,8 @@ impl Error for NodeError {} impl std::fmt::Display for NodeError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match self { - NodeError::IOError(err) => write!(f, "{}", err), + NodeError::ConfigParseError(err_msg) => write!(f, "{}", err_msg), + NodeError::IOError(err_msg) => write!(f, "{}", err_msg), NodeError::WasmProcessError(err) => write!(f, "{}", err), } } @@ -41,7 +45,7 @@ impl std::fmt::Display for NodeError { impl From for NodeError { fn from(err: IOError) -> Self { - NodeError::IOError(err) + NodeError::IOError(format!("{}", err)) } } diff --git a/examples/ipfs_node/src/imports.rs b/examples/ipfs_node/src/imports.rs new file mode 100644 index 00000000..046da9f9 --- /dev/null +++ b/examples/ipfs_node/src/imports.rs @@ -0,0 +1,54 @@ +/* + * 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 wasmer_core::vm::Ctx; +use wasmer_core::typed_func::DynamicFunc; + +pub(super) fn log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) { + use wasmer_core::memory::ptr::{Array, WasmPtr}; + + let wasm_ptr = WasmPtr::::new(offset as _); + match wasm_ptr.get_utf8_string(ctx.memory(0), size as _) { + Some(msg) => print!("{}", msg), + None => print!("ipfs node logger: incorrect UTF8 string's been supplied to logger"), + } +} + +pub(super) fn create_host_import_func(host_cmd: String) -> DynamicFunc<'static> { + use wasmer_core::types::Value; + use wasmer_core::types::Type; + use wasmer_core::types::FuncSig; + + let func = Box::new(move |ctx: &mut Ctx, inputs: &[Value]| -> Vec { + use wasmer_core::memory::ptr::{Array, WasmPtr}; + + // TODO: refactor this + let array_ptr = inputs[0].to_u128() as i32; + let array_size = inputs[1].to_u128() as i32; + + let wasm_ptr = WasmPtr::::new(array_ptr as _); + match wasm_ptr.get_utf8_string(ctx.memory(0), array_size as _) { + Some(msg) => print!("{}", msg), + None => print!("ipfs node logger: incorrect UTF8 string's been supplied to logger"), + } + vec![] + }); + + DynamicFunc::new( + std::sync::Arc::new(FuncSig::new(vec![Type::I32, Type::I32], vec![])), + func, + ) +} diff --git a/examples/ipfs_node/src/lib.rs b/examples/ipfs_node/src/lib.rs index e5fbb7b3..8ccaaa26 100644 --- a/examples/ipfs_node/src/lib.rs +++ b/examples/ipfs_node/src/lib.rs @@ -16,60 +16,9 @@ mod node; mod errors; +mod config; +mod imports; -use fce::IValue; -use fce::FCE; -use fce::FCEError; -use fce::FCEModuleConfig; -use fce::WasmProcess; - -const IPFS_NODE: &str = - "/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/ipfs_node_wit.wasm"; - -const IPFS_RPC: &str = - "/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/ipfs_rpc_wit.wasm"; - -fn main() { - let ipfs_node_bytes = std::fs::read(IPFS_NODE).unwrap(); - let ipfs_rpc_bytes = std::fs::read(IPFS_RPC).unwrap(); - - let mut fce = FCE::new(); - let config = FCEModuleConfig::default(); - - println!("loading ipfs node module"); - fce.load_module("node", &ipfs_node_bytes, config.clone()) - .expect("module successfully created"); - - println!("loading ipfs rpc module"); - fce.load_module("rpc", &ipfs_rpc_bytes, config.clone()) - .expect("module successfully created"); - - let result = fce - .call("node_rpc", "invoke", &[IValue::String("aaaa".to_string())]) - .unwrap(); - - println!("execution result {:?}", result); -} - -/* -fn logger_log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) { - use wasmer_runtime_core::memory::ptr::{Array, WasmPtr}; - - let wasm_ptr = WasmPtr::::new(offset as _); - match wasm_ptr.get_utf8_string(ctx.memory(0), size as _) { - Some(msg) => print!("{}", msg), - None => print!("fce logger: incorrect UTF8 string's been supplied to logger"), - } -} - - -fn ipfs_call(ctx: &mut Ctx, ptr: i32, size: i32) { - use wasmer_runtime_core::memory::ptr::{Array, WasmPtr}; - - let wasm_ptr = WasmPtr::::new(ptr as _); - match wasm_ptr.get_utf8_string(ctx.memory(0), size as _) { - Some(msg) => println!("host ipfs_call: {}", msg), - None => println!("fce logger: incorrect UTF8 string's been supplied to logger"), - } -} -*/ +pub use node::IpfsNode; +pub use node::NodeModule; +pub(crate) use imports::log_utf8_string; diff --git a/examples/ipfs_node/src/main.rs b/examples/ipfs_node/src/main.rs new file mode 100644 index 00000000..bcf2205e --- /dev/null +++ b/examples/ipfs_node/src/main.rs @@ -0,0 +1,45 @@ +/* + * 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. + */ + +mod node; +mod errors; +mod config; +mod imports; + +use node::IpfsNode; + +use std::path::PathBuf; + +const IPFS_MODULES_DIR: &str = "/Users/mike/dev/work/fluence/wasm/fce/bin/wasm_modules"; + +const IPFS_MODULES_CONFIG_PATH: &str = + "/Users/mike/dev/work/fluence/wasm/fce/examples/ipfs_node/Config.toml"; + +const IPFS_RPC: &str = "/Users/mike/dev/work/fluence/wasm/fce/bin/wasm_ipfs_rpc_wit.wasm"; + +fn main() { + let ipfs_rpc = std::fs::read(IPFS_RPC).unwrap(); + + let mut ipfs_node = IpfsNode::new( + PathBuf::from(IPFS_MODULES_DIR), + PathBuf::from(IPFS_MODULES_CONFIG_PATH), + ) + .unwrap(); + + let result = ipfs_node.rpc_call(&ipfs_rpc).unwrap(); + + println!("execution result {:?}", result); +} diff --git a/examples/ipfs_node/src/node.rs b/examples/ipfs_node/src/node.rs index b585d3f3..0102cf66 100644 --- a/examples/ipfs_node/src/node.rs +++ b/examples/ipfs_node/src/node.rs @@ -16,6 +16,8 @@ use super::errors::NodeError; +use wasmer_core::import::ImportObject; +use wasmer_runtime::{imports, func}; use fce::FCE; use fce::WasmProcess; use fce::NodeFunction; @@ -24,55 +26,61 @@ use fce::FCEModuleConfig; use std::fs; use std::path::PathBuf; +use crate::config::ModuleConfig; -pub(crate) struct IpfsNode { +pub struct IpfsNode { process: FCE, // names of core modules that is loaded to FCE module_names: Vec, + rpc_module_config: FCEModuleConfig, } +#[derive(Debug)] pub struct NodeModule<'a> { pub name: &'a str, pub functions: Vec>, } impl IpfsNode { - pub fn new(core_modules_dir: PathBuf, _config_file: PathBuf) -> Result { + pub fn new(core_modules_dir: PathBuf, config_file_path: PathBuf) -> Result { let mut wasm_process = FCE::new(); let mut module_names = Vec::new(); - let core_module_config = FCEModuleConfig::default(); + let mut core_modules_config = crate::config::parse_config_from_file(config_file_path)?; for entry in fs::read_dir(core_modules_dir)? { let path = entry?.path(); - if !path.is_dir() { - let module_name = path.file_name().unwrap(); - let module_name = module_name.to_os_string().into_string().unwrap(); - //.ok_or_else(|| Err(NodeError::IOError()))?; - - println!("module name is {}", module_name); - let module_bytes = fs::read(path.clone())?; - - wasm_process.load_module( - module_name.clone(), - &module_bytes, - core_module_config.clone(), - )?; - module_names.push(module_name); + if path.is_dir() { + continue; } + + let module_name = path.file_name().unwrap(); + let module_name = module_name + .to_os_string() + .into_string() + .map_err(|e| NodeError::IOError(format!("failed to read from {:?} file", e)))?; + + let module_bytes = fs::read(path.clone())?; + + let core_module_config = + Self::make_wasm_config(core_modules_config.modules_config.remove(&module_name))?; + wasm_process.load_module(module_name.clone(), &module_bytes, core_module_config)?; + module_names.push(module_name); } + let rpc_module_config = Self::make_wasm_config(core_modules_config.rpc_module_config)?; + Ok(Self { process: wasm_process, module_names, + rpc_module_config, }) } pub fn rpc_call(&mut self, wasm_rpc: &[u8]) -> Result, NodeError> { - let core_module_config = FCEModuleConfig::default(); let rpc_module_name = "ipfs_rpc"; self.process - .load_module(rpc_module_name, wasm_rpc, core_module_config)?; + .load_module(rpc_module_name, wasm_rpc, self.rpc_module_config.clone())?; let call_result = self.process.call( rpc_module_name, "invoke", @@ -96,4 +104,63 @@ impl IpfsNode { modules } + + fn make_wasm_config(config: Option) -> Result { + use crate::imports::create_host_import_func; + use crate::imports::log_utf8_string; + use wasmer_core::import::Namespace; + + let mut wasm_module_config = FCEModuleConfig::default(); + + let module_config = match config { + Some(config) => config, + None => return Ok(wasm_module_config), + }; + + if let Some(mem_pages_count) = module_config.mem_pages_count { + wasm_module_config.mem_pages_count = mem_pages_count; + } + + let mut namespace = Namespace::new(); + + if let Some(logger_enabled) = module_config.logger_enabled { + if logger_enabled { + namespace.insert("log_utf8_string", func!(log_utf8_string)); + } + } + + if let Some(imports) = module_config.imports { + for (import_name, host_cmd) in imports { + let host_import = create_host_import_func(host_cmd); + namespace.insert(import_name, host_import); + } + } + + let mut import_object = ImportObject::new(); + import_object.register("host", namespace); + + if let Some(wasi) = module_config.wasi { + if let Some(envs) = wasi.envs { + wasm_module_config.wasi_envs = envs; + } + + if let Some(preopened_files) = wasi.preopened_files { + wasm_module_config.wasi_preopened_files = preopened_files + .iter() + .map(|file| PathBuf::from(file)) + .collect::>(); + } + + if let Some(mapped_dirs) = wasi.mapped_dirs { + wasm_module_config.wasi_mapped_dirs = mapped_dirs + .into_iter() + .map(|(from, to)| (from, PathBuf::from(to))) + .collect::>(); + } + } + + wasm_module_config.imports = import_object; + + Ok(wasm_module_config) + } } diff --git a/examples/ipfs_node/wasm/ipfs_node/src/lib.rs b/examples/ipfs_node/wasm/ipfs_node/src/lib.rs index 5d5f6a05..0211b025 100644 --- a/examples/ipfs_node/wasm/ipfs_node/src/lib.rs +++ b/examples/ipfs_node/wasm/ipfs_node/src/lib.rs @@ -56,14 +56,11 @@ pub unsafe fn get(hash_ptr: *mut u8, hash_size: usize) { std::mem::forget(result); } -#[link(wasm_import_module = "logger")] +#[link(wasm_import_module = "host")] extern "C" { /// Writes a byte string of size bytes that starts from ptr to a logger. fn log_utf8_string(ptr: i32, size: i32); -} -#[link(wasm_import_module = "host")] -extern "C" { /// Put a file to ipfs, returns ipfs hash of the file. fn ipfs(ptr: i32, size: i32); } diff --git a/examples/ipfs_node/wasm/ipfs_node/wit b/examples/ipfs_node/wasm/ipfs_node/wit index 871def65..81e4f950 100644 --- a/examples/ipfs_node/wasm/ipfs_node/wit +++ b/examples/ipfs_node/wasm/ipfs_node/wit @@ -38,7 +38,7 @@ call-core 0 ;; call allocate arg.get 0 string.lower_memory - call-core 7 ;; call node.get + call-core 7 ;; call self.get call-core 3 ;; call get_result_ptr call-core 2 ;; call get_result_size string.lift_memory diff --git a/examples/ipfs_node/wasm/ipfs_rpc/src/lib.rs b/examples/ipfs_node/wasm/ipfs_rpc/src/lib.rs index bb1f50ec..37211b18 100644 --- a/examples/ipfs_node/wasm/ipfs_rpc/src/lib.rs +++ b/examples/ipfs_node/wasm/ipfs_rpc/src/lib.rs @@ -41,13 +41,13 @@ pub unsafe fn invoke(file_content_ptr: *mut u8, file_content_size: usize) { */ } -#[link(wasm_import_module = "logger")] +#[link(wasm_import_module = "host")] extern "C" { /// Writes a byte string of size bytes that starts from ptr to a logger. fn log_utf8_string(ptr: i32, size: i32); } -#[link(wasm_import_module = "node")] +#[link(wasm_import_module = "ipfs_node.wasm")] extern "C" { /// Put a file to ipfs, returns ipfs hash of the file. fn put(ptr: i32, size: i32); diff --git a/examples/ipfs_node/wasm/ipfs_rpc/wit b/examples/ipfs_node/wasm/ipfs_rpc/wit index c3dcd3d9..f3dc07c8 100644 --- a/examples/ipfs_node/wasm/ipfs_rpc/wit +++ b/examples/ipfs_node/wasm/ipfs_rpc/wit @@ -33,11 +33,11 @@ (@interface export "set_result_size" (func 4)) ;; 5 (@interface export "set_result_ptr" (func 4)) ;; 6 -(@interface import "node" "get" (func (type 5))) -(@interface import "node" "put" (func (type 5))) +(@interface import "ipfs_node.wasm" "get" (func (type 5))) +(@interface import "ipfs_node.wasm" "put" (func (type 5))) -(@interface import "node" "get" (func (type 7))) ;; 7 -(@interface import "node" "put" (func (type 8))) ;; 8 +(@interface import "ipfs_node.wasm" "get" (func (type 7))) ;; 7 +(@interface import "ipfs_node.wasm" "put" (func (type 8))) ;; 8 (@interface func (type 2) arg.get 0 @@ -58,7 +58,7 @@ arg.get 0 arg.get 1 string.lift_memory - call-core 7 ;; call node.get that returns string + call-core 7 ;; call ipfs_node.get that returns string dup string.size call-core 0 ;; call allocate diff --git a/fce/src/vm/config.rs b/fce/src/vm/config.rs index f2c65b88..f7d70503 100644 --- a/fce/src/vm/config.rs +++ b/fce/src/vm/config.rs @@ -25,12 +25,8 @@ pub struct FCEModuleConfig { /// Each Wasm pages is 65536 bytes long. pub mem_pages_count: u32, - /// If true, registers the logger Wasm module with name 'logger'. - /// This functionality is just for debugging, and this module will be disabled in future. - pub logger_enabled: bool, - /// Import object that will be used in module instantiation process. - pub import_object: ImportObject, + pub imports: ImportObject, /// Desired WASI version. pub wasi_version: WasiVersion, @@ -51,8 +47,7 @@ impl Default for FCEModuleConfig { Self { // 65536*1600 ~ 100 Mb mem_pages_count: 1600, - logger_enabled: true, - import_object: ImportObject::new(), + imports: ImportObject::new(), wasi_version: WasiVersion::Latest, wasi_envs: vec![], wasi_preopened_files: vec![], @@ -70,12 +65,6 @@ impl FCEModuleConfig { self } - #[allow(dead_code)] - pub fn with_logger_enable(mut self, logger_enable: bool) -> Self { - self.logger_enabled = logger_enable; - self - } - #[allow(dead_code)] pub fn with_wasi_version(mut self, wasi_version: WasiVersion) -> Self { self.wasi_version = wasi_version; diff --git a/fce/src/vm/fce.rs b/fce/src/vm/fce.rs index b5083244..059acd36 100644 --- a/fce/src/vm/fce.rs +++ b/fce/src/vm/fce.rs @@ -54,7 +54,10 @@ impl WasmProcess for FCE { Some(mut module) => unsafe { Ok(Arc::get_mut_unchecked(&mut module).call(func_name, argument)?) }, - None => Err(FCEError::NoSuchModule), + None => { + println!("no such module"); + Err(FCEError::NoSuchModule) + } } } @@ -70,7 +73,7 @@ impl WasmProcess for FCE { let _prepared_wasm_bytes = super::prepare::prepare_module(wasm_bytes, config.mem_pages_count)?; - let module = FCEModule::new(&wasm_bytes, config.import_object, &self.modules)?; + let module = FCEModule::new(&wasm_bytes, config.imports, &self.modules)?; match self.modules.entry(module_name.into()) { Entry::Vacant(entry) => { diff --git a/fce/src/vm/module/fce_module.rs b/fce/src/vm/module/fce_module.rs index eca2f389..cd990e53 100644 --- a/fce/src/vm/module/fce_module.rs +++ b/fce/src/vm/module/fce_module.rs @@ -104,10 +104,16 @@ impl FCEModule { ) -> Result<(&Vec, &Vec), FCEError> { match self.exports_funcs.get(function_name) { Some(func) => Ok((&func.inputs, &func.outputs)), - None => Err(FCEError::NoSuchFunction(format!( - "{} has't been found during its signature looking up", - function_name - ))), + None => { + for func in self.exports_funcs.iter() { + println!("{}", func.0); + } + + Err(FCEError::NoSuchFunction(format!( + "{} has't been found during its signature looking up", + function_name + ))) + } } } @@ -126,17 +132,23 @@ impl FCEModule { wit.implementations() .filter_map(|(adapter_function_type, core_function_type)| { - match wit.export_by_type(*core_function_type) { + match wit.exports_by_type(*core_function_type) { Some(export_function_name) => { - Some((adapter_function_type, *export_function_name)) + Some((adapter_function_type, export_function_name)) } // pass functions that aren't export None => None, } }) + .map(|(adapter_function_type, export_function_names)| { + export_function_names + .iter() + .map(move |export_function_name| (*adapter_function_type, export_function_name)) + }) + .flatten() .map(|(adapter_function_type, export_function_name)| { - let adapter_instructions = wit.adapter_by_type_r(*adapter_function_type)?; - let wit_type = wit.type_by_idx_r(*adapter_function_type)?; + let adapter_instructions = wit.adapter_by_type_r(adapter_function_type)?; + let wit_type = wit.type_by_idx_r(adapter_function_type)?; match wit_type { WITAstType::Function { @@ -211,15 +223,21 @@ impl FCEModule { let namespaces = wit .implementations() .filter_map(|(adapter_function_type, core_function_type)| { - match wit.import_by_type(*core_function_type) { - Some(import) => Some((adapter_function_type, *import)), - // skip functions that aren't export + match wit.imports_by_type(*core_function_type) { + Some(import) => Some((adapter_function_type, import)), + // skip functions that aren't import None => None, } }) + .map(|(adapter_function_type, import_function_names)| { + import_function_names + .iter() + .map(move |import_function_name| (*adapter_function_type, import_function_name)) + }) + .flatten() .map(|(adapter_function_type, (import_namespace, import_name))| { - let adapter_instructions = wit.adapter_by_type_r(*adapter_function_type)?; - let wit_type = wit.type_by_idx_r(*adapter_function_type)?; + let adapter_instructions = wit.adapter_by_type_r(adapter_function_type)?; + let wit_type = wit.type_by_idx_r(adapter_function_type)?; match wit_type { WITAstType::Function { inputs, .. } => { @@ -228,7 +246,7 @@ impl FCEModule { let wit_import = dyn_func_from_raw_import(inputs.clone(), inner_import); let mut namespace = Namespace::new(); - namespace.insert(import_name, wit_import); + namespace.insert(*import_name, wit_import); Ok((import_namespace.to_string(), namespace)) } @@ -238,12 +256,23 @@ impl FCEModule { ))), } }) - .collect::, FCEError>>()?; + .collect::, FCEError>>()?; let mut import_object = ImportObject::new(); - for (namespace_name, namespace) in namespaces { - import_object.register(namespace_name, namespace); + // TODO: refactor it + for (namespace_name, namespaces) in namespaces.iter_all() { + let mut result_namespace = Namespace::new(); + for namespace in namespaces { + use wasmer_core::import::LikeNamespace; + + result_namespace.insert( + namespace.get_exports()[0].0.clone(), + namespace.get_exports()[0].1.clone(), + ); + } + + import_object.register(namespace_name, result_namespace); } Ok(import_object) diff --git a/fce/src/vm/module/wit_instance.rs b/fce/src/vm/module/wit_instance.rs index 63c46a01..5e9a1a5e 100644 --- a/fce/src/vm/module/wit_instance.rs +++ b/fce/src/vm/module/wit_instance.rs @@ -91,7 +91,10 @@ impl WITInstance { WITFunction::from_import(module.clone(), import_name.to_string())?; Ok((start_index + idx as usize, func)) } - None => Err(FCEError::NoSuchModule), + None => { + println!("no such module: {}", import_namespace); + Err(FCEError::NoSuchModule) + } } }) .collect::, _>>() diff --git a/fce/src/wasm_process.rs b/fce/src/wasm_process.rs index c64f4576..249c087f 100644 --- a/fce/src/wasm_process.rs +++ b/fce/src/wasm_process.rs @@ -19,6 +19,7 @@ use super::FCEError; use super::IValue; use super::IType; +#[derive(Debug)] pub struct NodeFunction<'a> { pub name: &'a str, pub inputs: &'a Vec,