generalize ipfs node service

This commit is contained in:
vms 2020-06-06 21:34:13 +03:00
parent 8c845c9f37
commit 7d5ae2f9b0
20 changed files with 511 additions and 146 deletions

30
Cargo.lock generated
View File

@ -514,9 +514,20 @@ name = "ipfs_node"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fce", "fce",
"serde",
"serde_derive",
"serde_json",
"toml", "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]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@ -806,9 +817,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.110" version = "1.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" checksum = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -834,15 +845,26 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.110" version = "1.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" checksum = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "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]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.4.0" version = "1.4.0"

BIN
bin/wit_embedder Executable file

Binary file not shown.

View File

@ -35,13 +35,13 @@ pub struct FCEWITInterfaces<'a> {
types: Vec<WITAstType>, types: Vec<WITAstType>,
/// All the imported functions. /// All the imported functions.
imports: HashMap<CoreFunctionType, (ImportName<'a>, ImportNamespace<'a>)>, imports: MultiMap<CoreFunctionType, (ImportName<'a>, ImportNamespace<'a>)>,
/// All the adapters. /// All the adapters.
adapters: HashMap<AdapterFunctionType, Vec<Instruction>>, adapters: HashMap<AdapterFunctionType, Vec<Instruction>>,
/// All the exported functions. /// All the exported functions.
exports: HashMap<CoreFunctionType, ExportName<'a>>, exports: MultiMap<CoreFunctionType, ExportName<'a>>,
/// All the implementations. /// All the implementations.
adapter_type_to_core: MultiMap<AdapterFunctionType, CoreFunctionType>, adapter_type_to_core: MultiMap<AdapterFunctionType, CoreFunctionType>,
@ -54,7 +54,7 @@ impl<'a> FCEWITInterfaces<'a> {
.imports .imports
.into_iter() .into_iter()
.map(|import| (import.function_type, (import.namespace, import.name))) .map(|import| (import.function_type, (import.namespace, import.name)))
.collect::<HashMap<_, _>>(); .collect::<MultiMap<_, _>>();
let adapters = interfaces let adapters = interfaces
.adapters .adapters
@ -66,7 +66,7 @@ impl<'a> FCEWITInterfaces<'a> {
.exports .exports
.into_iter() .into_iter()
.map(|export| (export.function_type, export.name)) .map(|export| (export.function_type, export.name))
.collect::<HashMap<_, _>>(); .collect::<MultiMap<_, _>>();
let adapter_type_to_core = interfaces let adapter_type_to_core = interfaces
.implementations .implementations
@ -120,19 +120,19 @@ impl<'a> FCEWITInterfaces<'a> {
self.imports.iter() self.imports.iter()
} }
pub fn import_by_type( pub fn imports_by_type(
&self, &self,
import_type: CoreFunctionType, import_type: CoreFunctionType,
) -> Option<&(ImportName<'a>, ImportNamespace<'a>)> { ) -> Option<&Vec<(ImportName<'a>, ImportNamespace<'a>)>> {
self.imports.get(&import_type) self.imports.get_vec(&import_type)
} }
pub fn import_by_type_r( pub fn imports_by_type_r(
&self, &self,
import_type: CoreFunctionType, import_type: CoreFunctionType,
) -> Result<&(ImportName<'a>, ImportNamespace<'a>), FCEWITInterfacesError> { ) -> Result<&Vec<(ImportName<'a>, ImportNamespace<'a>)>, FCEWITInterfacesError> {
self.imports self.imports
.get(&import_type) .get_vec(&import_type)
.ok_or_else(|| FCEWITInterfacesError::NoSuchImport(import_type)) .ok_or_else(|| FCEWITInterfacesError::NoSuchImport(import_type))
} }
@ -153,14 +153,23 @@ impl<'a> FCEWITInterfaces<'a> {
.ok_or_else(|| FCEWITInterfacesError::NoSuchAdapter(adapter_type)) .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<Item = (&CoreFunctionType, &ExportName<'a>)> { pub fn exports(&self) -> impl Iterator<Item = (&CoreFunctionType, &ExportName<'a>)> {
self.exports.iter() self.exports.iter()
} }
pub fn exports_by_type(&self, export_type: u32) -> Option<&Vec<ExportName<'a>>> {
self.exports.get_vec(&export_type)
}
pub fn exports_by_type_r(
&self,
export_type: CoreFunctionType,
) -> Result<&Vec<ExportName<'a>>, FCEWITInterfacesError> {
self.exports
.get_vec(&export_type)
.ok_or_else(|| FCEWITInterfacesError::NoSuchImport(export_type))
}
pub fn implementations( pub fn implementations(
&self, &self,
) -> impl Iterator<Item = (&AdapterFunctionType, &CoreFunctionType)> { ) -> impl Iterator<Item = (&AdapterFunctionType, &CoreFunctionType)> {

View File

@ -6,4 +6,11 @@ edition = "2018"
[dependencies] [dependencies]
fce = { path = "../../fce" } fce = { path = "../../fce" }
wasmer-core = { package = "wasmer-runtime-core", version = "0.17.0" }
wasmer-runtime = "0.17.0"
toml = "0.5.6" toml = "0.5.6"
serde = { version = "1.0.111", features = ["derive"] }
serde_json = "1.0.53"
serde_derive = "1.0.111"

View File

@ -1,6 +1,17 @@
[ipfs_node] [[core_module]]
[imports] name = "ipfs_node.wasm"
mem_pages_count = 100
logger_enabled = true
[core_module.imports]
mysql = "/usr/bin/mysql"
ipfs = "/usr/bin/ipfs" ipfs = "/usr/bin/ipfs"
[wasi] [core_module.wasi]
preopened_dirs = ["/tmp"] envs = ["asdsad=sdaasd"]
preopened_files = ["/tmp/file1"]
mapped_dirs = { tmp = "/tmp", tmp2 = "/tmp" }
[rpc_module]
mem_pages_count = 100
logger_enabled = true

View File

@ -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<RawModuleConfig>,
pub rpc_module: Option<RawRPCModuleConfig>,
}
#[derive(Deserialize, Debug)]
pub(crate) struct RawModuleConfig {
pub name: String,
pub mem_pages_count: Option<u32>,
pub logger_enabled: Option<bool>,
pub imports: Option<toml::value::Table>,
pub wasi: Option<RawWASIConfig>,
}
#[derive(Deserialize, Debug)]
pub(crate) struct RawWASIConfig {
pub envs: Option<Vec<String>>,
pub preopened_files: Option<Vec<String>>,
pub mapped_dirs: Option<toml::value::Table>,
}
#[derive(Deserialize, Debug)]
pub(crate) struct RawRPCModuleConfig {
pub mem_pages_count: Option<u32>,
pub logger_enabled: Option<bool>,
pub wasi: Option<RawWASIConfig>,
}
#[derive(Debug)]
pub(crate) struct NodeConfig {
pub modules_config: HashMap<String, ModuleConfig>,
pub rpc_module_config: Option<ModuleConfig>,
}
#[derive(Debug)]
pub(crate) struct ModuleConfig {
pub mem_pages_count: Option<u32>,
pub logger_enabled: Option<bool>,
pub imports: Option<Vec<(String, String)>>,
pub wasi: Option<WASIConfig>,
}
#[derive(Debug)]
pub(crate) struct WASIConfig {
pub envs: Option<Vec<Vec<u8>>>,
pub preopened_files: Option<Vec<String>>,
pub mapped_dirs: Option<Vec<(String, String)>>,
}
pub(crate) fn parse_config_from_file(
config_file_path: std::path::PathBuf,
) -> Result<NodeConfig, NodeError> {
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<Vec<(String, String)>> = module.imports.map(|import| {
import
.into_iter()
.map(|(import_func_name, host_cmd)| {
(import_func_name, host_cmd.try_into::<String>().unwrap())
})
.collect::<Vec<_>>()
});
let wasi = module.wasi.map(|wasi| {
let envs = wasi
.envs
.map(|env| env.into_iter().map(|e| e.into_bytes()).collect::<Vec<_>>());
let mapped_dirs = wasi.mapped_dirs.map(|mapped_dir| {
mapped_dir
.into_iter()
.map(|(from, to)| (from, to.try_into::<String>().unwrap()))
.collect::<Vec<_>>()
});
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::<HashMap<_, _>>();
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::<Vec<_>>());
let mapped_dirs = wasi.mapped_dirs.map(|mapped_dir| {
mapped_dir
.into_iter()
.map(|(from, to)| (from, to.try_into::<String>().unwrap()))
.collect::<Vec<_>>()
});
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,
})
}

View File

@ -16,13 +16,16 @@
use fce::FCEError; use fce::FCEError;
use std::io::{Error as IOError, IoSliceMut}; use std::io::Error as IOError;
use std::error::Error; use std::error::Error;
#[derive(Debug)] #[derive(Debug)]
pub enum NodeError { pub enum NodeError {
/// An error related to config parsing.
ConfigParseError(String),
/// Various errors related to file io. /// Various errors related to file io.
IOError(IOError), IOError(String),
/// WIT doesn't contain such type. /// WIT doesn't contain such type.
WasmProcessError(FCEError), WasmProcessError(FCEError),
@ -33,7 +36,8 @@ impl Error for NodeError {}
impl std::fmt::Display for NodeError { impl std::fmt::Display for NodeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self { 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), NodeError::WasmProcessError(err) => write!(f, "{}", err),
} }
} }
@ -41,7 +45,7 @@ impl std::fmt::Display for NodeError {
impl From<IOError> for NodeError { impl From<IOError> for NodeError {
fn from(err: IOError) -> Self { fn from(err: IOError) -> Self {
NodeError::IOError(err) NodeError::IOError(format!("{}", err))
} }
} }

View File

@ -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::<u8, Array>::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<Value> {
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::<u8, Array>::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,
)
}

View File

@ -16,60 +16,9 @@
mod node; mod node;
mod errors; mod errors;
mod config;
mod imports;
use fce::IValue; pub use node::IpfsNode;
use fce::FCE; pub use node::NodeModule;
use fce::FCEError; pub(crate) use imports::log_utf8_string;
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::<u8, Array>::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::<u8, Array>::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"),
}
}
*/

View File

@ -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);
}

View File

@ -16,6 +16,8 @@
use super::errors::NodeError; use super::errors::NodeError;
use wasmer_core::import::ImportObject;
use wasmer_runtime::{imports, func};
use fce::FCE; use fce::FCE;
use fce::WasmProcess; use fce::WasmProcess;
use fce::NodeFunction; use fce::NodeFunction;
@ -24,55 +26,61 @@ use fce::FCEModuleConfig;
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use crate::config::ModuleConfig;
pub(crate) struct IpfsNode { pub struct IpfsNode {
process: FCE, process: FCE,
// names of core modules that is loaded to FCE // names of core modules that is loaded to FCE
module_names: Vec<String>, module_names: Vec<String>,
rpc_module_config: FCEModuleConfig,
} }
#[derive(Debug)]
pub struct NodeModule<'a> { pub struct NodeModule<'a> {
pub name: &'a str, pub name: &'a str,
pub functions: Vec<NodeFunction<'a>>, pub functions: Vec<NodeFunction<'a>>,
} }
impl IpfsNode { impl IpfsNode {
pub fn new(core_modules_dir: PathBuf, _config_file: PathBuf) -> Result<Self, NodeError> { pub fn new(core_modules_dir: PathBuf, config_file_path: PathBuf) -> Result<Self, NodeError> {
let mut wasm_process = FCE::new(); let mut wasm_process = FCE::new();
let mut module_names = Vec::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)? { for entry in fs::read_dir(core_modules_dir)? {
let path = entry?.path(); let path = entry?.path();
if !path.is_dir() { if path.is_dir() {
let module_name = path.file_name().unwrap(); continue;
let module_name = module_name.to_os_string().into_string().unwrap(); }
//.ok_or_else(|| Err(NodeError::IOError()))?;
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)))?;
println!("module name is {}", module_name);
let module_bytes = fs::read(path.clone())?; let module_bytes = fs::read(path.clone())?;
wasm_process.load_module( let core_module_config =
module_name.clone(), Self::make_wasm_config(core_modules_config.modules_config.remove(&module_name))?;
&module_bytes, wasm_process.load_module(module_name.clone(), &module_bytes, core_module_config)?;
core_module_config.clone(),
)?;
module_names.push(module_name); module_names.push(module_name);
} }
}
let rpc_module_config = Self::make_wasm_config(core_modules_config.rpc_module_config)?;
Ok(Self { Ok(Self {
process: wasm_process, process: wasm_process,
module_names, module_names,
rpc_module_config,
}) })
} }
pub fn rpc_call(&mut self, wasm_rpc: &[u8]) -> Result<Vec<IValue>, NodeError> { pub fn rpc_call(&mut self, wasm_rpc: &[u8]) -> Result<Vec<IValue>, NodeError> {
let core_module_config = FCEModuleConfig::default();
let rpc_module_name = "ipfs_rpc"; let rpc_module_name = "ipfs_rpc";
self.process 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( let call_result = self.process.call(
rpc_module_name, rpc_module_name,
"invoke", "invoke",
@ -96,4 +104,63 @@ impl IpfsNode {
modules modules
} }
fn make_wasm_config(config: Option<ModuleConfig>) -> Result<FCEModuleConfig, NodeError> {
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::<Vec<_>>();
}
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::<Vec<_>>();
}
}
wasm_module_config.imports = import_object;
Ok(wasm_module_config)
}
} }

View File

@ -56,14 +56,11 @@ pub unsafe fn get(hash_ptr: *mut u8, hash_size: usize) {
std::mem::forget(result); std::mem::forget(result);
} }
#[link(wasm_import_module = "logger")] #[link(wasm_import_module = "host")]
extern "C" { extern "C" {
/// Writes a byte string of size bytes that starts from ptr to a logger. /// Writes a byte string of size bytes that starts from ptr to a logger.
fn log_utf8_string(ptr: i32, size: i32); 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. /// Put a file to ipfs, returns ipfs hash of the file.
fn ipfs(ptr: i32, size: i32); fn ipfs(ptr: i32, size: i32);
} }

View File

@ -38,7 +38,7 @@
call-core 0 ;; call allocate call-core 0 ;; call allocate
arg.get 0 arg.get 0
string.lower_memory string.lower_memory
call-core 7 ;; call node.get call-core 7 ;; call self.get
call-core 3 ;; call get_result_ptr call-core 3 ;; call get_result_ptr
call-core 2 ;; call get_result_size call-core 2 ;; call get_result_size
string.lift_memory string.lift_memory

View File

@ -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" { extern "C" {
/// Writes a byte string of size bytes that starts from ptr to a logger. /// Writes a byte string of size bytes that starts from ptr to a logger.
fn log_utf8_string(ptr: i32, size: i32); fn log_utf8_string(ptr: i32, size: i32);
} }
#[link(wasm_import_module = "node")] #[link(wasm_import_module = "ipfs_node.wasm")]
extern "C" { extern "C" {
/// Put a file to ipfs, returns ipfs hash of the file. /// Put a file to ipfs, returns ipfs hash of the file.
fn put(ptr: i32, size: i32); fn put(ptr: i32, size: i32);

View File

@ -33,11 +33,11 @@
(@interface export "set_result_size" (func 4)) ;; 5 (@interface export "set_result_size" (func 4)) ;; 5
(@interface export "set_result_ptr" (func 4)) ;; 6 (@interface export "set_result_ptr" (func 4)) ;; 6
(@interface import "node" "get" (func (type 5))) (@interface import "ipfs_node.wasm" "get" (func (type 5)))
(@interface import "node" "put" (func (type 5))) (@interface import "ipfs_node.wasm" "put" (func (type 5)))
(@interface import "node" "get" (func (type 7))) ;; 7 (@interface import "ipfs_node.wasm" "get" (func (type 7))) ;; 7
(@interface import "node" "put" (func (type 8))) ;; 8 (@interface import "ipfs_node.wasm" "put" (func (type 8))) ;; 8
(@interface func (type 2) (@interface func (type 2)
arg.get 0 arg.get 0
@ -58,7 +58,7 @@
arg.get 0 arg.get 0
arg.get 1 arg.get 1
string.lift_memory string.lift_memory
call-core 7 ;; call node.get that returns string call-core 7 ;; call ipfs_node.get that returns string
dup dup
string.size string.size
call-core 0 ;; call allocate call-core 0 ;; call allocate

View File

@ -25,12 +25,8 @@ pub struct FCEModuleConfig {
/// Each Wasm pages is 65536 bytes long. /// Each Wasm pages is 65536 bytes long.
pub mem_pages_count: u32, 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. /// Import object that will be used in module instantiation process.
pub import_object: ImportObject, pub imports: ImportObject,
/// Desired WASI version. /// Desired WASI version.
pub wasi_version: WasiVersion, pub wasi_version: WasiVersion,
@ -51,8 +47,7 @@ impl Default for FCEModuleConfig {
Self { Self {
// 65536*1600 ~ 100 Mb // 65536*1600 ~ 100 Mb
mem_pages_count: 1600, mem_pages_count: 1600,
logger_enabled: true, imports: ImportObject::new(),
import_object: ImportObject::new(),
wasi_version: WasiVersion::Latest, wasi_version: WasiVersion::Latest,
wasi_envs: vec![], wasi_envs: vec![],
wasi_preopened_files: vec![], wasi_preopened_files: vec![],
@ -70,12 +65,6 @@ impl FCEModuleConfig {
self self
} }
#[allow(dead_code)]
pub fn with_logger_enable(mut self, logger_enable: bool) -> Self {
self.logger_enabled = logger_enable;
self
}
#[allow(dead_code)] #[allow(dead_code)]
pub fn with_wasi_version(mut self, wasi_version: WasiVersion) -> Self { pub fn with_wasi_version(mut self, wasi_version: WasiVersion) -> Self {
self.wasi_version = wasi_version; self.wasi_version = wasi_version;

View File

@ -54,7 +54,10 @@ impl WasmProcess for FCE {
Some(mut module) => unsafe { Some(mut module) => unsafe {
Ok(Arc::get_mut_unchecked(&mut module).call(func_name, argument)?) 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 = let _prepared_wasm_bytes =
super::prepare::prepare_module(wasm_bytes, config.mem_pages_count)?; 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()) { match self.modules.entry(module_name.into()) {
Entry::Vacant(entry) => { Entry::Vacant(entry) => {

View File

@ -104,10 +104,16 @@ impl FCEModule {
) -> Result<(&Vec<IType>, &Vec<IType>), FCEError> { ) -> Result<(&Vec<IType>, &Vec<IType>), FCEError> {
match self.exports_funcs.get(function_name) { match self.exports_funcs.get(function_name) {
Some(func) => Ok((&func.inputs, &func.outputs)), Some(func) => Ok((&func.inputs, &func.outputs)),
None => Err(FCEError::NoSuchFunction(format!( None => {
for func in self.exports_funcs.iter() {
println!("{}", func.0);
}
Err(FCEError::NoSuchFunction(format!(
"{} has't been found during its signature looking up", "{} has't been found during its signature looking up",
function_name function_name
))), )))
}
} }
} }
@ -126,17 +132,23 @@ impl FCEModule {
wit.implementations() wit.implementations()
.filter_map(|(adapter_function_type, core_function_type)| { .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(export_function_name) => {
Some((adapter_function_type, *export_function_name)) Some((adapter_function_type, export_function_name))
} }
// pass functions that aren't export // pass functions that aren't export
None => None, 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)| { .map(|(adapter_function_type, export_function_name)| {
let adapter_instructions = wit.adapter_by_type_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)?; let wit_type = wit.type_by_idx_r(adapter_function_type)?;
match wit_type { match wit_type {
WITAstType::Function { WITAstType::Function {
@ -211,15 +223,21 @@ impl FCEModule {
let namespaces = wit let namespaces = wit
.implementations() .implementations()
.filter_map(|(adapter_function_type, core_function_type)| { .filter_map(|(adapter_function_type, core_function_type)| {
match wit.import_by_type(*core_function_type) { match wit.imports_by_type(*core_function_type) {
Some(import) => Some((adapter_function_type, *import)), Some(import) => Some((adapter_function_type, import)),
// skip functions that aren't export // skip functions that aren't import
None => None, 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))| { .map(|(adapter_function_type, (import_namespace, import_name))| {
let adapter_instructions = wit.adapter_by_type_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)?; let wit_type = wit.type_by_idx_r(adapter_function_type)?;
match wit_type { match wit_type {
WITAstType::Function { inputs, .. } => { WITAstType::Function { inputs, .. } => {
@ -228,7 +246,7 @@ impl FCEModule {
let wit_import = dyn_func_from_raw_import(inputs.clone(), inner_import); let wit_import = dyn_func_from_raw_import(inputs.clone(), inner_import);
let mut namespace = Namespace::new(); let mut namespace = Namespace::new();
namespace.insert(import_name, wit_import); namespace.insert(*import_name, wit_import);
Ok((import_namespace.to_string(), namespace)) Ok((import_namespace.to_string(), namespace))
} }
@ -238,12 +256,23 @@ impl FCEModule {
))), ))),
} }
}) })
.collect::<Result<HashMap<String, Namespace>, FCEError>>()?; .collect::<Result<multimap::MultiMap<String, Namespace>, FCEError>>()?;
let mut import_object = ImportObject::new(); let mut import_object = ImportObject::new();
for (namespace_name, namespace) in namespaces { // TODO: refactor it
import_object.register(namespace_name, namespace); 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) Ok(import_object)

View File

@ -91,7 +91,10 @@ impl WITInstance {
WITFunction::from_import(module.clone(), import_name.to_string())?; WITFunction::from_import(module.clone(), import_name.to_string())?;
Ok((start_index + idx as usize, func)) Ok((start_index + idx as usize, func))
} }
None => Err(FCEError::NoSuchModule), None => {
println!("no such module: {}", import_namespace);
Err(FCEError::NoSuchModule)
}
} }
}) })
.collect::<Result<HashMap<_, _>, _>>() .collect::<Result<HashMap<_, _>, _>>()

View File

@ -19,6 +19,7 @@ use super::FCEError;
use super::IValue; use super::IValue;
use super::IType; use super::IType;
#[derive(Debug)]
pub struct NodeFunction<'a> { pub struct NodeFunction<'a> {
pub name: &'a str, pub name: &'a str,
pub inputs: &'a Vec<IType>, pub inputs: &'a Vec<IType>,