introduce ipfs service

This commit is contained in:
vms 2020-06-05 23:12:02 +03:00
parent 5d7fdec0ee
commit 2bbbb9323d
28 changed files with 372 additions and 140 deletions

15
Cargo.lock generated
View File

@ -514,10 +514,9 @@ dependencies = [
[[package]] [[package]]
name = "ipfs_node" name = "ipfs_node"
version = "0.1.0" version = "0.1.0"
dependencies = [
[[package]] "fce",
name = "ipfs_rpc" ]
version = "0.1.0"
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
@ -1035,6 +1034,14 @@ version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasm_ipfs_node"
version = "0.1.0"
[[package]]
name = "wasm_ipfs_rpc"
version = "0.1.0"
[[package]] [[package]]
name = "wasmer-clif-backend" name = "wasmer-clif-backend"
version = "0.17.0" version = "0.17.0"

View File

@ -1,9 +1,10 @@
[workspace] [workspace]
members = [ members = [
"crates/fce_wit_interfaces", "crates/fce_wit_interfaces",
"examples/export_test",
"examples/ipfs_node", "examples/ipfs_node",
"examples/ipfs_rpc", "examples/ipfs_node/wasm/ipfs_node",
"examples/ipfs_node/wasm/ipfs_rpc",
"examples/simple_greeting",
"fce", "fce",
"tools/wit_embedder", "tools/wit_embedder",
] ]

View File

@ -4,7 +4,5 @@ version = "0.1.0"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
edition = "2018" edition = "2018"
[lib] [dependencies]
name = "ipfs_node" fce = { path = "../../fce" }
path = "src/lib.rs"
crate-type = ["cdylib"]

View File

@ -0,0 +1,52 @@
/*
* 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 fce::FCEError;
use std::io::{Error as IOError, IoSliceMut};
use std::error::Error;
#[derive(Debug)]
pub enum NodeError {
/// Various errors related to file io.
IOError(IOError),
/// WIT doesn't contain such type.
WasmProcessError(FCEError),
}
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::WasmProcessError(err) => write!(f, "{}", err),
}
}
}
impl From<IOError> for NodeError {
fn from(err: IOError) -> Self {
NodeError::IOError(err)
}
}
impl From<FCEError> for NodeError {
fn from(err: FCEError) -> Self {
NodeError::WasmProcessError(err)
}
}

View File

@ -14,56 +14,62 @@
* limitations under the License. * limitations under the License.
*/ */
#![allow(clippy::missing_safety_doc)] mod node;
mod errors;
mod mem; use fce::IValue;
mod result; use fce::FCE;
use fce::FCEError;
use fce::FCEModuleConfig;
use fce::WasmProcess;
use crate::result::{RESULT_PTR, RESULT_SIZE}; const IPFS_NODE: &str =
"/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/ipfs_node_wit.wasm";
#[no_mangle] const IPFS_RPC: &str =
pub unsafe fn put(file_content_ptr: *mut u8, file_content_size: usize) { "/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/ipfs_rpc_wit.wasm";
let file_content =
String::from_raw_parts(file_content_ptr, file_content_size, file_content_size);
let msg = format!("from Wasm node: file content is {}\n", file_content); fn main() {
log_utf8_string(msg.as_ptr() as _, msg.len() as _); let ipfs_node_bytes = std::fs::read(IPFS_NODE).unwrap();
let ipfs_rpc_bytes = std::fs::read(IPFS_RPC).unwrap();
let cmd = format!("put {}", file_content); let mut fce = FCE::new();
ipfs(cmd.as_ptr() as _, cmd.len() as _); let config = FCEModuleConfig::default();
let result = "Hello from IPFS node, take your hash".to_string(); println!("loading ipfs node module");
fce.load_module("node", &ipfs_node_bytes, config.clone())
.expect("module successfully created");
*RESULT_PTR.get_mut() = result.as_ptr() as _; println!("loading ipfs rpc module");
*RESULT_SIZE.get_mut() = result.len(); fce.load_module("rpc", &ipfs_rpc_bytes, config.clone())
std::mem::forget(result); .expect("module successfully created");
let result = fce
.call("node_rpc", "invoke", &[IValue::String("aaaa".to_string())])
.unwrap();
println!("execution result {:?}", result);
} }
#[no_mangle] /*
pub unsafe fn get(hash_ptr: *mut u8, hash_size: usize) { fn logger_log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) {
let hash = String::from_raw_parts(hash_ptr, hash_size, hash_size); use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};
let msg = format!("from Wasm node: file content is {}\n", hash); let wasm_ptr = WasmPtr::<u8, Array>::new(offset as _);
log_utf8_string(msg.as_ptr() as _, msg.len() as _); match wasm_ptr.get_utf8_string(ctx.memory(0), size as _) {
Some(msg) => print!("{}", msg),
let cmd = format!("get {}", hash); None => print!("fce logger: incorrect UTF8 string's been supplied to logger"),
ipfs(cmd.as_ptr() as _, cmd.len() as _); }
let result = "Hello from IPFS node, take your file".to_string();
*RESULT_PTR.get_mut() = result.as_ptr() as _;
*RESULT_SIZE.get_mut() = result.len();
std::mem::forget(result);
} }
#[link(wasm_import_module = "logger")]
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")] fn ipfs_call(ctx: &mut Ctx, ptr: i32, size: i32) {
extern "C" { use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};
/// Put a file to ipfs, returns ipfs hash of the file.
fn ipfs(ptr: i32, size: i32); 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,99 @@
/*
* 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 super::errors::NodeError;
use fce::FCE;
use fce::WasmProcess;
use fce::NodeFunction;
use fce::IValue;
use fce::FCEModuleConfig;
use std::fs;
use std::path::PathBuf;
pub(crate) struct IpfsNode {
process: FCE,
// names of core modules that is loaded to FCE
module_names: Vec<String>,
}
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> {
let mut wasm_process = FCE::new();
let mut module_names = Vec::new();
let core_module_config = FCEModuleConfig::default();
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);
}
}
Ok(Self {
process: wasm_process,
module_names,
})
}
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)?;
let call_result = self.process.call(
rpc_module_name,
"invoke",
&[IValue::String("test".to_string())],
)?;
self.process.unload_module(rpc_module_name)?;
Ok(call_result)
}
pub fn get_interface(&self) -> Vec<NodeModule> {
let mut modules = Vec::with_capacity(self.module_names.len());
for module_name in self.module_names.iter() {
let functions = self.process.get_interface(module_name).unwrap();
modules.push(NodeModule {
name: module_name,
functions,
})
}
modules
}
}

View File

@ -0,0 +1,10 @@
[package]
name = "wasm_ipfs_node"
version = "0.1.0"
authors = ["Fluence Labs"]
edition = "2018"
[lib]
name = "wasm_ipfs_node"
path = "src/lib.rs"
crate-type = ["cdylib"]

View File

@ -0,0 +1,69 @@
/*
* 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.
*/
#![allow(clippy::missing_safety_doc)]
mod mem;
mod result;
use crate::result::{RESULT_PTR, RESULT_SIZE};
#[no_mangle]
pub unsafe fn put(file_content_ptr: *mut u8, file_content_size: usize) {
let file_content =
String::from_raw_parts(file_content_ptr, file_content_size, file_content_size);
let msg = format!("from Wasm node: file content is {}\n", file_content);
log_utf8_string(msg.as_ptr() as _, msg.len() as _);
let cmd = format!("put {}", file_content);
ipfs(cmd.as_ptr() as _, cmd.len() as _);
let result = "Hello from IPFS node, take your hash".to_string();
*RESULT_PTR.get_mut() = result.as_ptr() as _;
*RESULT_SIZE.get_mut() = result.len();
std::mem::forget(result);
}
#[no_mangle]
pub unsafe fn get(hash_ptr: *mut u8, hash_size: usize) {
let hash = String::from_raw_parts(hash_ptr, hash_size, hash_size);
let msg = format!("from Wasm node: file content is {}\n", hash);
log_utf8_string(msg.as_ptr() as _, msg.len() as _);
let cmd = format!("get {}", hash);
ipfs(cmd.as_ptr() as _, cmd.len() as _);
let result = "Hello from IPFS node, take your file".to_string();
*RESULT_PTR.get_mut() = result.as_ptr() as _;
*RESULT_SIZE.get_mut() = result.len();
std::mem::forget(result);
}
#[link(wasm_import_module = "logger")]
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);
}

View File

@ -1,10 +1,10 @@
[package] [package]
name = "ipfs_rpc" name = "wasm_ipfs_rpc"
version = "0.1.0" version = "0.1.0"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
edition = "2018" edition = "2018"
[lib] [lib]
name = "ipfs_rpc" name = "wasm_ipfs_rpc"
path = "src/lib.rs" path = "src/lib.rs"
crate-type = ["cdylib"] crate-type = ["cdylib"]

30
fce/src/lib.rs Normal file
View File

@ -0,0 +1,30 @@
/*
* 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.
*/
#![warn(rust_2018_idioms)]
#![feature(get_mut_unchecked)]
#![feature(new_uninit)]
mod vm;
mod misc;
mod wasm_process;
pub use vm::FCE;
pub use vm::FCEError;
pub use vm::FCEModuleConfig;
pub use vm::IValue;
pub use vm::IType;
pub use wasm_process::WasmProcess;
pub use wasm_process::NodeFunction;

View File

@ -1,77 +0,0 @@
/*
* 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.
*/
#![warn(rust_2018_idioms)]
#![feature(get_mut_unchecked)]
#![feature(new_uninit)]
mod vm;
mod misc;
use vm::IValue;
use vm::FCE;
use vm::FCEModuleConfig;
use vm::FCEService;
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.register_module("node", &ipfs_node_bytes, config.clone())
.expect("module successfully created");
println!("loading ipfs rpc module");
fce.register_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

@ -145,6 +145,6 @@ impl From<FCEWITInterfacesError> for FCEError {
impl From<()> for FCEError { impl From<()> for FCEError {
fn from(_err: ()) -> Self { fn from(_err: ()) -> Self {
FCEError::IncorrectWIT(format!("failed to parse instructions for adapter type")) FCEError::IncorrectWIT("failed to parse instructions for adapter type".to_string())
} }
} }

View File

@ -16,6 +16,8 @@
use super::instance::FCEModule; use super::instance::FCEModule;
use super::*; use super::*;
use crate::WasmProcess;
use crate::NodeFunction;
use std::sync::Arc; use std::sync::Arc;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
@ -40,7 +42,7 @@ impl Default for FCE {
} }
} }
impl FCEService for FCE { impl WasmProcess for FCE {
fn call( fn call(
&mut self, &mut self,
module_name: &str, module_name: &str,
@ -56,7 +58,7 @@ impl FCEService for FCE {
} }
} }
fn register_module<S>( fn load_module<S>(
&mut self, &mut self,
module_name: S, module_name: S,
wasm_bytes: &[u8], wasm_bytes: &[u8],
@ -79,7 +81,7 @@ impl FCEService for FCE {
} }
} }
fn unregister_module(&mut self, module_name: &str) -> Result<(), FCEError> { fn unload_module(&mut self, module_name: &str) -> Result<(), FCEError> {
match self.modules.entry(module_name.to_string()) { match self.modules.entry(module_name.to_string()) {
Entry::Vacant(_) => Err(FCEError::NoSuchModule), Entry::Vacant(_) => Err(FCEError::NoSuchModule),
@ -89,4 +91,22 @@ impl FCEService for FCE {
} }
} }
} }
fn get_interface(&self, module_name: &str) -> Result<Vec<NodeFunction<'_>>, FCEError> {
match self.modules.get(module_name) {
Some(module) => {
let signatures = module
.as_ref()
.get_exports_signatures()
.map(|(name, inputs, outputs)| NodeFunction {
name,
inputs,
outputs,
})
.collect::<Vec<_>>();
Ok(signatures)
}
None => Err(FCEError::NoSuchModule),
}
}
} }

View File

@ -110,6 +110,14 @@ impl FCEModule {
} }
} }
pub fn get_exports_signatures(
&self,
) -> impl Iterator<Item = (&String, &Vec<IType>, &Vec<IType>)> {
self.exports_funcs
.iter()
.map(|(func_name, func)| (func_name, &func.inputs, &func.outputs))
}
fn instantiate_wit_exports( fn instantiate_wit_exports(
wit: &FCEWITInterfaces<'_>, wit: &FCEWITInterfaces<'_>,
) -> Result<HashMap<String, WITModuleFunc>, FCEError> { ) -> Result<HashMap<String, WITModuleFunc>, FCEError> {

View File

@ -16,13 +16,11 @@
mod fce; mod fce;
mod instance; mod instance;
mod fce_service;
mod config; mod config;
mod prepare; mod prepare;
mod errors; mod errors;
pub use fce::FCE; pub use fce::FCE;
pub use fce_service::FCEService;
pub use config::FCEModuleConfig; pub use config::FCEModuleConfig;
pub use errors::FCEError; pub use errors::FCEError;
pub use instance::{IType, IValue}; pub use instance::{IType, IValue};

View File

@ -14,12 +14,19 @@
* limitations under the License. * limitations under the License.
*/ */
use super::config::FCEModuleConfig; use super::FCEModuleConfig;
use super::errors::FCEError; use super::FCEError;
use super::IValue; use super::IValue;
use super::IType;
/// Describes a service behaviour in the Fluence network. pub struct NodeFunction<'a> {
pub trait FCEService { pub name: &'a str,
pub inputs: &'a Vec<IType>,
pub outputs: &'a Vec<IType>,
}
/// Describes a run computation node behaviour in the Fluence network.
pub trait WasmProcess {
/// Invokes a module supplying byte array and expecting byte array with some outcome back. /// Invokes a module supplying byte array and expecting byte array with some outcome back.
fn call( fn call(
&mut self, &mut self,
@ -29,7 +36,8 @@ pub trait FCEService {
) -> Result<Vec<IValue>, FCEError>; ) -> Result<Vec<IValue>, FCEError>;
/// Registers new module in the FCE Service. /// Registers new module in the FCE Service.
fn register_module<S>( /// TODO:
fn load_module<S>(
&mut self, &mut self,
module_name: S, module_name: S,
wasm_bytes: &[u8], wasm_bytes: &[u8],
@ -39,5 +47,8 @@ pub trait FCEService {
S: Into<String>; S: Into<String>;
/// Unregisters previously registered module. /// Unregisters previously registered module.
fn unregister_module(&mut self, module_name: &str) -> Result<(), FCEError>; fn unload_module(&mut self, module_name: &str) -> Result<(), FCEError>;
/// Returns signatures of all exported functions by this module.
fn get_interface(&self, module_name: &str) -> Result<Vec<NodeFunction<'_>>, FCEError>;
} }