Skip to content

Commit

Permalink
Initial Plugin Implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
canewsin committed Aug 13, 2022
1 parent f0c63e6 commit c870280
Show file tree
Hide file tree
Showing 9 changed files with 1,092 additions and 186 deletions.
1,042 changes: 899 additions & 143 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ futures-util = "0.3.21"
html-escape = "0.2.11"
actix-web-actors = "4.1.0"
rayon = "1.5.3"
mut_static = "5.0.0"

[dependencies.rusqlite]
features = ["serde_json", "bundled"]
Expand Down Expand Up @@ -64,6 +65,10 @@ git = "https://github.com/decentnetwork/zerucontent.git"
git = "https://github.com/decentnetwork/decentnet_protocol.git"
features = ["full"]

[dependencies.wit-bindgen-wasmer]
git = "https://github.com/wasmerio/wit-bindgen.git"
branch="wasmer"

[features]
default = ["userio", "blockstorage"]
blockstorage = []
Expand Down
11 changes: 11 additions & 0 deletions assets/plugins/manifest.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: func() -> string

description: func() -> string

version: func() -> s64

permissions: func() -> list<string>

min-engine-version: func() -> s64

max-engine-version: func() -> s64
3 changes: 3 additions & 0 deletions assets/plugins/path_provider.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
get-storage-path: func(data-path: string) -> string

get-file-path: func(data-path: string, block-id: string) -> string
7 changes: 6 additions & 1 deletion src/environment.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
use std::{collections::HashMap, env::current_dir, fs, path::PathBuf, str::FromStr};

use clap::{Arg, ArgMatches, Command};
use lazy_static::lazy_static;
use mut_static::MutStatic;
use rand::Rng;
use serde_json::json;
use std::{collections::HashMap, env::current_dir, fs, path::PathBuf, str::FromStr};

use crate::{
core::{error::Error, site::models::SiteStorage, user::User},
io::utils::{load_sites_file, load_trackers, load_users_file},
plugins::*,
utils::gen_peer_id,
};

lazy_static! {
pub static ref PLUGINS: Vec<Plugin> = load_plugins();
pub static ref PATH_PROVIDER_PLUGINS: MutStatic<Vec<PathProviderPlugin>> = load_path_provider_plugins();
pub static ref DEF_ASSETS_PATH: PathBuf = PathBuf::from("assets/");
pub static ref DEF_PEERS_FILE_PATH: PathBuf = DEF_ASSETS_PATH.join("peers.txt");
pub static ref DEF_TRACKERS_FILE_PATH: PathBuf = DEF_ASSETS_PATH.join("trackers.txt");
Expand Down
23 changes: 11 additions & 12 deletions src/io/site.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ use zerucontent::{Content, File as ZFile};
use crate::{
core::{error::*, io::*, peer::*, site::*},
discovery::tracker::IpPort,
environment::ENV,
environment::{ENV, PATH_PROVIDER_PLUGINS},
io::utils::check_file_integrity,
net::Protocol,
plugins::BlockStorage,
plugins::*,
};

impl Site {
Expand Down Expand Up @@ -166,9 +166,9 @@ impl Site {
_peer: Option<Peer>,
) -> Result<bool, Error> {
let (parent, path) = if let Some(file) = file.clone() {
if cfg!(feature = "blockstorage") && Self::use_block_storage() {
let file_path = BlockStorage::get_block_file_path(self, &file.sha512);
let parent = BlockStorage::get_block_storage_path(self);
if !PATH_PROVIDER_PLUGINS.read().unwrap().is_empty() {
let file_path = get_file_path(&file.sha512).into();
let parent: PathBuf = get_storage_path().into();
(parent, file_path)
} else {
let path = self.site_path().join(&inner_path);
Expand Down Expand Up @@ -311,13 +311,12 @@ impl Site {
let mut tasks = Vec::new();
for (inner_path, file) in files {
let hash = file.sha512.clone();
let (site_path, inner_path) =
if cfg!(feature = "blockstorage") && Self::use_block_storage() {
let path = BlockStorage::get_block_storage_path(self);
(path, hash.clone())
} else {
(self.site_path(), inner_path)
};
let (site_path, inner_path) = if !PATH_PROVIDER_PLUGINS.read().unwrap().is_empty() {
let path = get_storage_path().into();
(path, hash.clone())
} else {
(self.site_path(), inner_path)
};
let task = check_file_integrity(site_path, inner_path, hash);
tasks.push(task);
}
Expand Down
28 changes: 0 additions & 28 deletions src/plugins/blockstorage.rs

This file was deleted.

83 changes: 81 additions & 2 deletions src/plugins/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,85 @@
mod blockstorage;
mod path_provider;
mod peer_db;

pub mod web;

pub use blockstorage::BlockStorage;
use std::path::PathBuf;

use log::error;
pub use path_provider::*;

use wit_bindgen_wasmer::wasmer::{imports, Cranelift, Module, Store};

use self::manifest::Manifest;

wit_bindgen_wasmer::import!("assets/plugins/manifest.wit");

pub fn load_plugins() -> Vec<Plugin> {
let engine = Cranelift::default();
let mut store = Store::new(engine);
let plugins_dir = PathBuf::from("plugins");
if plugins_dir.exists() {
let list = std::fs::read_dir(plugins_dir).unwrap();
let plugins = list.filter_map(|entry| {
let path = entry.unwrap().path();
if path.is_file() && path.extension().unwrap() == "wasm" {
Some(path)
} else {
None
}
});
let mut plugins_loaded = Vec::new();
for plugin in plugins {
let bytes = std::fs::read(&plugin).unwrap();
let module = Module::new(&store, &bytes);
if let Ok(module) = module {
let mut imports = imports! {};
let funs = Manifest::instantiate(&mut store, &module, &mut imports);
if let Ok((manifest, _)) = funs {
let name = manifest.name(&mut store).unwrap();
let description = manifest.description(&mut store).unwrap();
let version = manifest.version(&mut store).unwrap();
let permissions = manifest
.permissions(&mut store)
.unwrap()
.into_iter()
.map(|s| match s.as_str() {
"path_provider" => Permission::PathProvider,
_ => unimplemented!(),
})
.collect();
let path = plugin.clone();
let plugin = Plugin {
name,
description,
version,
permissions,
path,
};
plugins_loaded.push(plugin);
} else {
let error = funs.err().unwrap();
error!("Failed to load plugin {:?}", error);
}
}
}
plugins_loaded
} else {
vec![]
}
}

#[allow(dead_code)]
#[derive(Debug)]
pub struct Plugin {
name: String,
description: String,
version: i64,
permissions: Vec<Permission>,
path: PathBuf,
}

#[derive(Debug, PartialEq)]
enum Permission {
PathProvider,
}
76 changes: 76 additions & 0 deletions src/plugins/path_provider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use std::ops::DerefMut;

use mut_static::MutStatic;
use wit_bindgen_wasmer::wasmer::{imports, Cranelift, Module, Store};

use crate::environment::{ENV, PATH_PROVIDER_PLUGINS, PLUGINS};

use self::path_provider::PathProvider;

use super::Permission;
use log::error;

wit_bindgen_wasmer::import!("assets/plugins/path_provider.wit");

pub fn get_storage_path() -> String {
let mut plugin = (*PATH_PROVIDER_PLUGINS).write().unwrap();
let plugin = plugin.deref_mut().first_mut().unwrap();
let path = plugin
.provider
.get_storage_path(&mut plugin.store, &(&*ENV).data_path.display().to_string());
if path.is_err() {
error!("Failed to get storage path");
}
path.unwrap()
}

pub fn get_file_path(block_id: &str) -> String {
let mut plugin = (*PATH_PROVIDER_PLUGINS).write().unwrap();
let plugin = plugin.deref_mut().first_mut().unwrap();
let path = plugin.provider.get_file_path(
&mut plugin.store,
&(&*ENV).data_path.display().to_string(),
block_id,
);
if path.is_err() {
error!("Failed to get storage path");
}
path.unwrap()
}

pub fn load_path_provider_plugins() -> MutStatic<Vec<PathProviderPlugin>> {
// let plugins_dir = PathBuf::from("plugins");
let plugins = (&*PLUGINS)
.iter()
.filter(|p| p.permissions.contains(&Permission::PathProvider));
let mut plugins_loaded = Vec::new();
for plugin in plugins {
let engine = Cranelift::default();
let mut store = Store::new(engine);
let bytes = std::fs::read(&plugin.path).unwrap();
let module = Module::new(&store, &bytes);
if let Ok(module) = module {
let mut imports = imports! {};
let funs = PathProvider::instantiate(&mut store, &module, &mut imports);
if let Ok((provider, _)) = funs {
let plugin = PathProviderPlugin {
store,
module,
provider,
};
plugins_loaded.push(plugin);
} else {
let error = funs.err().unwrap();
error!("Failed to load plugin {:?}", error);
}
}
}
MutStatic::from(plugins_loaded)
}

#[allow(unused)]
pub struct PathProviderPlugin {
store: Store,
module: Module,
provider: PathProvider,
}

0 comments on commit c870280

Please sign in to comment.