Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,232 changes: 81 additions & 2,151 deletions Cargo.lock

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
[workspace]
members = [
"crates/file-explorer",
"crates/file-explorer-plugin",
"crates/file-explorer-proto",
"crates/file-explorer-ui",
# "crates/file-explorer",
# "crates/file-explorer-plugin",
# "crates/file-explorer-proto",
# "crates/file-explorer-ui",
"crates/hello-world-plugin",
"crates/http-server",
"crates/http-server-plugin",
]
Expand Down
65 changes: 33 additions & 32 deletions crates/file-explorer-plugin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ struct FileExplorerPlugin {

#[async_trait]
impl Plugin for FileExplorerPlugin {
async fn call(&self, parts: Parts, body: Bytes) -> Result<Response<Full<Bytes>>, PluginError> {
fn call(&self, parts: Parts, body: Bytes) -> Result<Response<Full<Bytes>>, PluginError> {
self.rt
.block_on(async move { self.handle(parts, body).await })
}
Expand All @@ -84,37 +84,38 @@ impl FileExplorerPlugin {
parts: Parts,
body: Bytes,
) -> Result<Response<Full<Bytes>>, PluginError> {
tracing::info!("Handling request: {:?}", parts);

if parts.uri.path().starts_with("/api/v1") {
self.handle_api(parts, body).await
} else {
let path = parts.uri.path();
let path = path.strip_prefix('/').unwrap_or(path);

if let Some(file) = Assets::get(path) {
let content_type = mime_guess::from_path(path).first_or_octet_stream();
let content_type = HeaderValue::from_str(content_type.as_ref()).unwrap();
let body = Full::new(Bytes::from(file.data.to_vec()));
let mut response = Response::new(body);
let mut headers = response.headers().clone();

headers.append(CONTENT_TYPE, content_type);
*response.headers_mut() = headers;

return Ok(response);
}

let index = Assets::get("index.html").unwrap();
let body = Full::new(Bytes::from(index.data.to_vec()));
let mut response = Response::new(body);
let mut headers = response.headers().clone();

headers.append(CONTENT_TYPE, "text/html".try_into().unwrap());
*response.headers_mut() = headers;

Ok(response)
}
Ok(Response::new(Full::new(Bytes::from("Unsupported method"))))
// tracing::info!("Handling request: {:?}", parts);

// if parts.uri.path().starts_with("/api/v1") {
// self.handle_api(parts, body).await
// } else {
// let path = parts.uri.path();
// let path = path.strip_prefix('/').unwrap_or(path);

// if let Some(file) = Assets::get(path) {
// let content_type = mime_guess::from_path(path).first_or_octet_stream();
// let content_type = HeaderValue::from_str(content_type.as_ref()).unwrap();
// let body = Full::new(Bytes::from(file.data.to_vec()));
// let mut response = Response::new(body);
// let mut headers = response.headers().clone();

// headers.append(CONTENT_TYPE, content_type);
// *response.headers_mut() = headers;

// return Ok(response);
// }

// let index = Assets::get("index.html").unwrap();
// let body = Full::new(Bytes::from(index.data.to_vec()));
// let mut response = Response::new(body);
// let mut headers = response.headers().clone();

// headers.append(CONTENT_TYPE, "text/html".try_into().unwrap());
// *response.headers_mut() = headers;

// Ok(response)
// }
}

async fn handle_api(
Expand Down
25 changes: 25 additions & 0 deletions crates/hello-world-plugin/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "hello-world-plugin"
version = "0.0.0"
authors = ["Esteban Borai <[email protected]>"]
edition = "2021"
publish = false

[lib]
crate-type = ["cdylib"]

[dependencies]
anyhow = { workspace = true }
async-trait = { workspace = true }
bytes = { workspace = true }
futures = { workspace = true }
http = { workspace = true }
http-body-util = { workspace = true }
hyper = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tokio = { workspace = true, features = ["fs", "rt-multi-thread", "signal", "macros"] }
tracing = { workspace = true }
tracing-subscriber = { workspace = true, features = ["env-filter"] }

http-server-plugin = { workspace = true }
8 changes: 8 additions & 0 deletions crates/hello-world-plugin/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.PHONY: default

default:
@echo No default target.

release:
@echo Building hello-world-plugin
cargo b --release
57 changes: 57 additions & 0 deletions crates/hello-world-plugin/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::path::PathBuf;
use std::sync::Arc;

use anyhow::Result;
use async_trait::async_trait;
use http::request::Parts;
use http_body_util::Full;
use hyper::body::Bytes;
use hyper::Response;
use tokio::runtime::Handle;

use http_server_plugin::{export_plugin, Plugin, PluginError, PluginRegistrar};

export_plugin!(register);

const PLUGIN_NAME: &str = "hello-world";

#[allow(improper_ctypes_definitions)]
extern "C" fn register(_: PathBuf, rt: Arc<Handle>, registrar: &mut dyn PluginRegistrar) {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.init();

registrar.register_function(
PLUGIN_NAME,
Arc::new(HelloWorldPlugin::new(rt)),
);
}

struct HelloWorldPlugin {
rt: Arc<Handle>,
}

#[async_trait]
impl Plugin for HelloWorldPlugin {
#[no_mangle]
fn call(&self, parts: Parts, body: Bytes) -> Result<Response<Full<Bytes>>, PluginError> {
println!("Test block on:");
self.handle(parts, body)
}
}

impl HelloWorldPlugin {
fn new(rt: Arc<Handle>) -> Self {
Self {
rt,
}
}

fn handle(
&self,
_: Parts,
_: Bytes,
) -> Result<Response<Full<Bytes>>, PluginError> {
Ok(Response::new(Full::new(Bytes::from("Hello World"))))
}
}
4 changes: 1 addition & 3 deletions crates/http-server-plugin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ pub mod config;
use std::path::PathBuf;
use std::sync::Arc;

use async_trait::async_trait;
use http::request::Parts;
use http_body_util::Full;
use hyper::body::Bytes;
Expand All @@ -13,9 +12,8 @@ use tokio::runtime::Handle;
pub static CORE_VERSION: &str = env!("CARGO_PKG_VERSION");
pub static RUSTC_VERSION: &str = env!("RUSTC_VERSION");

#[async_trait]
pub trait Plugin: Send + Sync {
async fn call(&self, parts: Parts, body: Bytes) -> Result<Response<Full<Bytes>>, PluginError>;
fn call(&self, parts: Parts, body: Bytes) -> Result<Response<Full<Bytes>>, PluginError>;
}

#[derive(Debug)]
Expand Down
10 changes: 9 additions & 1 deletion crates/http-server/src/bin/cli/command/setup.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::fs::{create_dir_all, write};
use std::fs::{create_dir_all, remove_file, write};

use anyhow::Result;
use clap::Parser;
Expand Down Expand Up @@ -33,6 +33,14 @@ impl SetupOpt {
"Installing File Explorer Plugin at: {}",
file_explorer_plugin_path.display()
);

if let Err(err) = remove_file(&file_explorer_plugin_path) {
eprint!(
"Failed to delete previous plugin version at {}\nError: {err}",
file_explorer_plugin_path.display()
);
}

write(&file_explorer_plugin_path, FILE_EXPLORER_PLUGIN_BYTES)?;
}

Expand Down
2 changes: 1 addition & 1 deletion crates/http-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
pub const HTTP_SERVER_PLUGINS_DIRNAME: &str = "plugins";
pub const DEFAULT_PLUGIN_NAME: &str = "file_explorer.plugin.httprs";
pub const FILE_EXPLORER_PLUGIN_BYTES: &[u8] =
include_bytes!("../inline/file_explorer.plugin.httprs");
include_bytes!("../../../target/release/libhello_world_plugin.dylib");

Check failure on line 12 in crates/http-server/src/lib.rs

View workflow job for this annotation

GitHub Actions / Builds for ubuntu-latest

couldn't read `crates/http-server/src/../../../target/release/libhello_world_plugin.dylib`: No such file or directory (os error 2)

Check failure on line 12 in crates/http-server/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

couldn't read `crates/http-server/src/../../../target/release/libhello_world_plugin.dylib`: No such file or directory (os error 2)

pub fn install_path() -> Result<PathBuf> {
let Some(home) = home_dir() else {
Expand Down
4 changes: 2 additions & 2 deletions crates/http-server/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ impl Server {
let svc = tower::service_fn(|req: Request<Incoming>| async {
let (parts, body) = req.into_parts();
let body = body.collect().await.unwrap().to_bytes();

match plugin_store.run("file-explorer", parts, body).await {
println!("Exec: hello-world");
match plugin_store.run("hello-world", parts, body).await {
Ok(res) => Ok::<
Response<http_body_util::Full<hyper::body::Bytes>>,
Infallible,
Expand Down
14 changes: 4 additions & 10 deletions crates/http-server/src/server/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ pub struct PluginProxy {

#[async_trait]
impl Plugin for PluginProxy {
async fn call(&self, parts: Parts, bytes: Bytes) -> Result<Response<Full<Bytes>>, PluginError> {
self.function.call(parts, bytes).await
#[no_mangle]
fn call(&self, parts: Parts, bytes: Bytes) -> Result<Response<Full<Bytes>>, PluginError> {
self.function.call(parts, bytes)
}
}

Expand Down Expand Up @@ -103,14 +104,7 @@ impl PluginStore {
bytes: Bytes,
) -> Result<Response<Full<Bytes>>, PluginError> {
let function_proxy = self.get(plugin).await.unwrap();
let join_handle = self
.handle
.spawn(async move { function_proxy.call(parts, bytes).await })
.await;

join_handle.map_err(|err| PluginError::SpawnError {
err: err.to_string(),
})?
function_proxy.call(parts, bytes)
}
}

Expand Down
Loading