Skip to content

Commit 1f72cb0

Browse files
committed
feat: plugin store and plugin error
1 parent d986aee commit 1f72cb0

File tree

4 files changed

+56
-64
lines changed

4 files changed

+56
-64
lines changed

crates/file-explorer-plugin/src/lib.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use file_explorer::{Entry, FileExplorer};
2323
use file_explorer_proto::{BreadcrumbItem, DirectoryEntry, DirectoryIndex, EntryType, Sort};
2424
use file_explorer_ui::Assets;
2525
use http_server_plugin::config::read_from_path;
26-
use http_server_plugin::{export_plugin, Function, InvocationError, PluginRegistrar};
26+
use http_server_plugin::{export_plugin, Plugin, PluginError, PluginRegistrar};
2727

2828
use self::utils::{decode_uri, encode_uri, PERCENT_ENCODE_SET};
2929

@@ -61,12 +61,8 @@ struct FileExplorerPlugin {
6161
}
6262

6363
#[async_trait]
64-
impl Function for FileExplorerPlugin {
65-
async fn call(
66-
&self,
67-
parts: Parts,
68-
body: Bytes,
69-
) -> Result<Response<Full<Bytes>>, InvocationError> {
64+
impl Plugin for FileExplorerPlugin {
65+
async fn call(&self, parts: Parts, body: Bytes) -> Result<Response<Full<Bytes>>, PluginError> {
7066
self.rt
7167
.block_on(async move { self.handle(parts, body).await })
7268
}
@@ -87,7 +83,7 @@ impl FileExplorerPlugin {
8783
&self,
8884
parts: Parts,
8985
body: Bytes,
90-
) -> Result<Response<Full<Bytes>>, InvocationError> {
86+
) -> Result<Response<Full<Bytes>>, PluginError> {
9187
tracing::info!("Handling request: {:?}", parts);
9288

9389
if parts.uri.path().starts_with("/api/v1") {
@@ -125,7 +121,7 @@ impl FileExplorerPlugin {
125121
&self,
126122
parts: Parts,
127123
body: Bytes,
128-
) -> Result<Response<Full<Bytes>>, InvocationError> {
124+
) -> Result<Response<Full<Bytes>>, PluginError> {
129125
let path = Self::parse_req_uri(parts.uri.clone()).unwrap();
130126

131127
match parts.method {
@@ -174,7 +170,7 @@ impl FileExplorerPlugin {
174170
&self,
175171
parts: Parts,
176172
body: Bytes,
177-
) -> Result<Response<Full<Bytes>>, InvocationError> {
173+
) -> Result<Response<Full<Bytes>>, PluginError> {
178174
// Extract the `multipart/form-data` boundary from the headers.
179175
let boundary = parts
180176
.headers

crates/http-server-plugin/src/lib.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,13 @@ pub static CORE_VERSION: &str = env!("CARGO_PKG_VERSION");
1414
pub static RUSTC_VERSION: &str = env!("RUSTC_VERSION");
1515

1616
#[async_trait]
17-
pub trait Function: Send + Sync {
18-
async fn call(
19-
&self,
20-
parts: Parts,
21-
body: Bytes,
22-
) -> Result<Response<Full<Bytes>>, InvocationError>;
17+
pub trait Plugin: Send + Sync {
18+
async fn call(&self, parts: Parts, body: Bytes) -> Result<Response<Full<Bytes>>, PluginError>;
2319
}
2420

2521
#[derive(Debug)]
26-
pub enum InvocationError {
27-
InvalidArgumentCount { expected: usize, found: usize },
22+
pub enum PluginError {
23+
SpawnError { err: String },
2824
Other { msg: String },
2925
}
3026

@@ -37,7 +33,7 @@ pub struct PluginDeclaration {
3733
}
3834

3935
pub trait PluginRegistrar {
40-
fn register_function(&mut self, name: &str, function: Arc<dyn Function>);
36+
fn register_function(&mut self, name: &str, function: Arc<dyn Plugin>);
4137
}
4238

4339
#[macro_export]

crates/http-server/src/server/mod.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ use tokio::runtime::Runtime;
2020
use tower::ServiceBuilder;
2121
use tower_http::cors::{Any, CorsLayer};
2222

23-
use crate::plugins_path;
24-
2523
use self::config::Config;
26-
use self::plugin::ExternalFunctions;
24+
use self::plugin::PluginStore;
2725

2826
const ALL_INTERFACES_IPV4: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
2927

@@ -39,8 +37,7 @@ impl Server {
3937
pub async fn run(self, rt: Arc<Runtime>) -> Result<()> {
4038
let addr = SocketAddr::from((self.config.host, self.config.port));
4139
let listener = TcpListener::bind(addr).await?;
42-
let functions = Arc::new(ExternalFunctions::new());
43-
let plugin_library = plugins_path()?.join("file_explorer.plugin.httprs");
40+
let plugin_store = Arc::new(PluginStore::new());
4441
let config = PathBuf::from_str("./config.toml")?;
4542
let handle = Arc::new(rt.handle().to_owned());
4643

@@ -53,15 +50,15 @@ impl Server {
5350
}
5451

5552
unsafe {
56-
functions
57-
.load(Arc::clone(&handle), config, plugin_library)
53+
plugin_store
54+
.load(Arc::clone(&handle), config, "file_explorer.plugin.httprs")
5855
.await?;
5956
}
6057

6158
loop {
6259
let (stream, _) = listener.accept().await?;
6360
let io = TokioIo::new(stream);
64-
let functions = Arc::clone(&functions);
61+
let plugin_store = Arc::clone(&plugin_store);
6562
let cors = if self.config.cors {
6663
Some(
6764
CorsLayer::new()
@@ -73,12 +70,12 @@ impl Server {
7370
};
7471

7572
handle.spawn(async move {
76-
let functions = Arc::clone(&functions);
73+
let plugin_store = Arc::clone(&plugin_store);
7774
let svc = tower::service_fn(|req: Request<Incoming>| async {
7875
let (parts, body) = req.into_parts();
7976
let body = body.collect().await.unwrap().to_bytes();
8077

81-
match functions.call("file-explorer", parts, body).await {
78+
match plugin_store.run("file-explorer", parts, body).await {
8279
Ok(res) => Ok::<
8380
Response<http_body_util::Full<hyper::body::Bytes>>,
8481
Infallible,

crates/http-server/src/server/plugin.rs

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::collections::HashMap;
2-
use std::ffi::OsStr;
3-
use std::io;
2+
use std::io::{Error as IOError, Result as IOResult};
43
use std::path::PathBuf;
54
use std::sync::Arc;
65

@@ -13,48 +12,44 @@ use libloading::Library;
1312
use tokio::runtime::Handle;
1413
use tokio::sync::Mutex;
1514

16-
use http_server_plugin::{
17-
Function, InvocationError, PluginDeclaration, CORE_VERSION, RUSTC_VERSION,
18-
};
15+
use http_server_plugin::{Plugin, PluginDeclaration, PluginError, CORE_VERSION, RUSTC_VERSION};
1916

20-
/// A proxy object which wraps a [`Function`] and makes sure it can't outlive
17+
use crate::plugins_path;
18+
19+
/// A proxy object which wraps a [`Plugin`] and makes sure it can't outlive
2120
/// the library it came from.
2221
#[derive(Clone)]
23-
pub struct FunctionProxy {
24-
function: Arc<dyn Function>,
22+
pub struct PluginProxy {
23+
function: Arc<dyn Plugin>,
2524
_lib: Arc<Library>,
2625
}
2726

2827
#[async_trait]
29-
impl Function for FunctionProxy {
30-
async fn call(
31-
&self,
32-
parts: Parts,
33-
bytes: Bytes,
34-
) -> Result<Response<Full<Bytes>>, InvocationError> {
28+
impl Plugin for PluginProxy {
29+
async fn call(&self, parts: Parts, bytes: Bytes) -> Result<Response<Full<Bytes>>, PluginError> {
3530
self.function.call(parts, bytes).await
3631
}
3732
}
3833

39-
pub struct ExternalFunctions {
34+
pub struct PluginStore {
35+
functions: Mutex<HashMap<String, PluginProxy>>,
4036
handle: Arc<Handle>,
41-
functions: Mutex<HashMap<String, FunctionProxy>>,
4237
libraries: Mutex<Vec<Arc<Library>>>,
4338
}
4439

45-
impl Default for ExternalFunctions {
40+
impl Default for PluginStore {
4641
fn default() -> Self {
4742
Self::new()
4843
}
4944
}
5045

51-
impl ExternalFunctions {
52-
pub fn new() -> ExternalFunctions {
46+
impl PluginStore {
47+
pub fn new() -> Self {
5348
let handle = Arc::new(Handle::current());
5449

55-
ExternalFunctions {
56-
handle,
50+
Self {
5751
functions: Mutex::new(HashMap::default()),
52+
handle,
5853
libraries: Mutex::new(Vec::new()),
5954
}
6055
}
@@ -65,20 +60,26 @@ impl ExternalFunctions {
6560
///
6661
/// This function is unsafe because it loads a shared library and calls
6762
/// functions from it.
68-
pub async unsafe fn load<P: AsRef<OsStr>>(
63+
pub async unsafe fn load(
6964
&self,
7065
rt_handle: Arc<Handle>,
7166
config_path: PathBuf,
72-
library_path: P,
73-
) -> io::Result<()> {
74-
let library = Arc::new(Library::new(library_path).unwrap());
67+
plugin_filename: &str,
68+
) -> IOResult<()> {
69+
let plugin_path = plugins_path()
70+
.map_err(|err| IOError::other(format!("Failed to retrieve plugin path: {err}")))?
71+
.join(plugin_filename);
72+
let library = Library::new(&plugin_path).map_err(|err| {
73+
IOError::other(format!("Failed to load plugin from {plugin_path:?}: {err}"))
74+
})?;
75+
let library = Arc::new(library);
7576
let decl = library
7677
.get::<*mut PluginDeclaration>(b"PLUGIN_DECLARATION\0")
7778
.unwrap()
7879
.read();
7980

8081
if decl.rustc_version != RUSTC_VERSION || decl.core_version != CORE_VERSION {
81-
return Err(io::Error::new(io::ErrorKind::Other, "Version mismatch"));
82+
return Err(IOError::other("Version Mismatch."));
8283
}
8384

8485
let mut registrar = PluginRegistrar::new(Arc::clone(&library));
@@ -91,28 +92,30 @@ impl ExternalFunctions {
9192
Ok(())
9293
}
9394

94-
async fn get_function(&self, func: &str) -> Option<FunctionProxy> {
95+
async fn get(&self, func: &str) -> Option<PluginProxy> {
9596
self.functions.lock().await.get(func).cloned()
9697
}
9798

98-
pub async fn call(
99+
pub async fn run(
99100
&self,
100-
func: &str,
101+
plugin: &str,
101102
parts: Parts,
102103
bytes: Bytes,
103-
) -> Result<Response<Full<Bytes>>, InvocationError> {
104-
let function_proxy = self.get_function(func).await.unwrap();
104+
) -> Result<Response<Full<Bytes>>, PluginError> {
105+
let function_proxy = self.get(plugin).await.unwrap();
105106
let join_handle = self
106107
.handle
107108
.spawn(async move { function_proxy.call(parts, bytes).await })
108109
.await;
109110

110-
join_handle.unwrap()
111+
join_handle.map_err(|err| PluginError::SpawnError {
112+
err: err.to_string(),
113+
})?
111114
}
112115
}
113116

114117
struct PluginRegistrar {
115-
functions: HashMap<String, FunctionProxy>,
118+
functions: HashMap<String, PluginProxy>,
116119
lib: Arc<Library>,
117120
}
118121

@@ -126,8 +129,8 @@ impl PluginRegistrar {
126129
}
127130

128131
impl http_server_plugin::PluginRegistrar for PluginRegistrar {
129-
fn register_function(&mut self, name: &str, function: Arc<dyn Function>) {
130-
let proxy = FunctionProxy {
132+
fn register_function(&mut self, name: &str, function: Arc<dyn Plugin>) {
133+
let proxy = PluginProxy {
131134
function,
132135
_lib: Arc::clone(&self.lib),
133136
};

0 commit comments

Comments
 (0)