mirror of
https://github.com/fluencelabs/marine.git
synced 2024-12-12 14:55:32 +00:00
generalize ipfs node service
This commit is contained in:
parent
8c845c9f37
commit
7d5ae2f9b0
30
Cargo.lock
generated
30
Cargo.lock
generated
@ -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"
|
||||
|
BIN
bin/wit_embedder
Executable file
BIN
bin/wit_embedder
Executable file
Binary file not shown.
@ -35,13 +35,13 @@ pub struct FCEWITInterfaces<'a> {
|
||||
types: Vec<WITAstType>,
|
||||
|
||||
/// All the imported functions.
|
||||
imports: HashMap<CoreFunctionType, (ImportName<'a>, ImportNamespace<'a>)>,
|
||||
imports: MultiMap<CoreFunctionType, (ImportName<'a>, ImportNamespace<'a>)>,
|
||||
|
||||
/// All the adapters.
|
||||
adapters: HashMap<AdapterFunctionType, Vec<Instruction>>,
|
||||
|
||||
/// All the exported functions.
|
||||
exports: HashMap<CoreFunctionType, ExportName<'a>>,
|
||||
exports: MultiMap<CoreFunctionType, ExportName<'a>>,
|
||||
|
||||
/// All the implementations.
|
||||
adapter_type_to_core: MultiMap<AdapterFunctionType, CoreFunctionType>,
|
||||
@ -54,7 +54,7 @@ impl<'a> FCEWITInterfaces<'a> {
|
||||
.imports
|
||||
.into_iter()
|
||||
.map(|import| (import.function_type, (import.namespace, import.name)))
|
||||
.collect::<HashMap<_, _>>();
|
||||
.collect::<MultiMap<_, _>>();
|
||||
|
||||
let adapters = interfaces
|
||||
.adapters
|
||||
@ -66,7 +66,7 @@ impl<'a> FCEWITInterfaces<'a> {
|
||||
.exports
|
||||
.into_iter()
|
||||
.map(|export| (export.function_type, export.name))
|
||||
.collect::<HashMap<_, _>>();
|
||||
.collect::<MultiMap<_, _>>();
|
||||
|
||||
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<Item = (&CoreFunctionType, &ExportName<'a>)> {
|
||||
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(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (&AdapterFunctionType, &CoreFunctionType)> {
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
175
examples/ipfs_node/src/config.rs
Normal file
175
examples/ipfs_node/src/config.rs
Normal 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,
|
||||
})
|
||||
}
|
@ -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<IOError> for NodeError {
|
||||
fn from(err: IOError) -> Self {
|
||||
NodeError::IOError(err)
|
||||
NodeError::IOError(format!("{}", err))
|
||||
}
|
||||
}
|
||||
|
||||
|
54
examples/ipfs_node/src/imports.rs
Normal file
54
examples/ipfs_node/src/imports.rs
Normal 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,
|
||||
)
|
||||
}
|
@ -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::<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"),
|
||||
}
|
||||
}
|
||||
*/
|
||||
pub use node::IpfsNode;
|
||||
pub use node::NodeModule;
|
||||
pub(crate) use imports::log_utf8_string;
|
||||
|
45
examples/ipfs_node/src/main.rs
Normal file
45
examples/ipfs_node/src/main.rs
Normal 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);
|
||||
}
|
@ -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<String>,
|
||||
rpc_module_config: FCEModuleConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NodeModule<'a> {
|
||||
pub name: &'a str,
|
||||
pub functions: Vec<NodeFunction<'a>>,
|
||||
}
|
||||
|
||||
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 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()))?;
|
||||
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)))?;
|
||||
|
||||
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(),
|
||||
)?;
|
||||
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<Vec<IValue>, 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<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)
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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) => {
|
||||
|
@ -104,10 +104,16 @@ impl FCEModule {
|
||||
) -> Result<(&Vec<IType>, &Vec<IType>), FCEError> {
|
||||
match self.exports_funcs.get(function_name) {
|
||||
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",
|
||||
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::<Result<HashMap<String, Namespace>, FCEError>>()?;
|
||||
.collect::<Result<multimap::MultiMap<String, Namespace>, 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)
|
||||
|
@ -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::<Result<HashMap<_, _>, _>>()
|
||||
|
@ -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<IType>,
|
||||
|
Loading…
Reference in New Issue
Block a user