sync
This commit is contained in:
parent
489dd0f14b
commit
a3b46410e8
7 changed files with 283 additions and 0 deletions
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "gpt-sandbox"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = { version = "1.39.2", features = ["full"] }
|
||||||
|
tracing = "0.1.40"
|
||||||
|
tracing-subscriber = "0.3.18"
|
||||||
|
libloading = "0.8.5"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = ["plugin-lib"]
|
12
plugin-lib/Cargo.toml
Normal file
12
plugin-lib/Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "plugin-lib"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
#tokio = { version = "1.39.2", features = ["full"] }
|
||||||
|
#tracing = "0.1.40"
|
||||||
|
gpt-sandbox = { path = "../" }
|
1
plugin-lib/rustfmt.toml
Normal file
1
plugin-lib/rustfmt.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hard_tabs=true
|
79
plugin-lib/src/lib.rs
Normal file
79
plugin-lib/src/lib.rs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
use gpt_sandbox::tokio;
|
||||||
|
use gpt_sandbox::tokio::runtime::Runtime;
|
||||||
|
use gpt_sandbox::tracing;
|
||||||
|
|
||||||
|
use gpt_sandbox::tracing::Dispatch;
|
||||||
|
use gpt_sandbox::AsyncFn;
|
||||||
|
use gpt_sandbox::AsyncFnReturnType;
|
||||||
|
use gpt_sandbox::PluginError;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
|
// TODO fix static mut black magic, it can and will set fire eventually
|
||||||
|
static mut FUNCTION_MAP: Option<Arc<Mutex<HashMap<String, AsyncFn>>>> = None;
|
||||||
|
static REACTOR: ::std::sync::OnceLock<Arc<Runtime>> = ::std::sync::OnceLock::new();
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn register_reactor(tokio_reactor: Arc<Runtime>) {
|
||||||
|
REACTOR.set(tokio_reactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn register_dispatcher(dispatcher: Dispatch) {
|
||||||
|
//tracing::subscriber::set_global_default(dispatcher).unwrap();
|
||||||
|
tracing::dispatcher::set_global_default(dispatcher).unwrap();
|
||||||
|
info!("test");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn register_functions(function_map: Arc<Mutex<HashMap<String, AsyncFn>>>) {
|
||||||
|
info!("registering functions...");
|
||||||
|
unsafe {
|
||||||
|
FUNCTION_MAP = Some(Arc::clone(&function_map));
|
||||||
|
}
|
||||||
|
|
||||||
|
let example_function: AsyncFn = Box::new(example_function);
|
||||||
|
|
||||||
|
info!("writing functions...");
|
||||||
|
|
||||||
|
function_map
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.insert("example_function".to_string(), example_function);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn unregister_functions() {
|
||||||
|
unsafe {
|
||||||
|
if let Some(function_map) = &FUNCTION_MAP {
|
||||||
|
function_map.lock().unwrap().remove("example_function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//pub fn example_function() -> AsyncFnReturnType {
|
||||||
|
// REACTOR.get().unwrap().spawn(async {
|
||||||
|
// tracing::info!("example_function is running");
|
||||||
|
// // Simulate some async work
|
||||||
|
// tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
|
||||||
|
// tracing::info!("example_function completed");
|
||||||
|
// // Return an error for demonstration
|
||||||
|
// Err(PluginError::FunctionError(
|
||||||
|
// "Something went wrong".to_string(),
|
||||||
|
// ))
|
||||||
|
// })
|
||||||
|
//}
|
||||||
|
|
||||||
|
pub async fn example_function() -> AsyncFnReturnType {
|
||||||
|
REACTOR.get().unwrap().spawn(async {
|
||||||
|
tracing::info!("example_function is running");
|
||||||
|
// Simulate some async work
|
||||||
|
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
|
||||||
|
tracing::info!("example_function completed");
|
||||||
|
// Return an error for demonstration
|
||||||
|
Err(PluginError::FunctionError(
|
||||||
|
"Something went wrong".to_string(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hard_tabs=true
|
29
src/lib.rs
Normal file
29
src/lib.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
pub use tokio;
|
||||||
|
pub use tracing;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PluginError {
|
||||||
|
FunctionError(String),
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Display for PluginError {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
match self {
|
||||||
|
PluginError::FunctionError(msg) => write!(f, "Function error: {}", msg),
|
||||||
|
PluginError::Other(msg) => write!(f, "Other error: {}", msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for PluginError {}
|
||||||
|
|
||||||
|
//pub type AsyncFnReturnType = Result<(), PluginError>;
|
||||||
|
//pub type AsyncFn = Box<
|
||||||
|
// dyn Fn()
|
||||||
|
// -> std::pin::Pin<Box<dyn std::future::Future<Output = AsyncFnReturnType> + Send + Sync>>
|
||||||
|
// + Send
|
||||||
|
// + Sync,
|
||||||
|
//>;
|
||||||
|
pub type AsyncFnReturnType = tokio::task::JoinHandle<Result<(), PluginError>>;
|
||||||
|
pub type AsyncFn = Box<dyn Fn() -> AsyncFnReturnType + Send + Sync>;
|
148
src/main.rs
Normal file
148
src/main.rs
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
use gpt_sandbox::AsyncFn;
|
||||||
|
use libloading::{Library, Symbol};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
use tokio::task;
|
||||||
|
use tracing::{error, info, Dispatch};
|
||||||
|
|
||||||
|
struct PluginContainer {
|
||||||
|
function_map: Arc<Mutex<HashMap<String, AsyncFn>>>,
|
||||||
|
libraries: Arc<Mutex<HashMap<String, Library>>>,
|
||||||
|
reactor: Arc<Runtime>,
|
||||||
|
tracing_dispatcher: Dispatch,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginContainer {
|
||||||
|
fn new(reactor: Arc<tokio::runtime::Runtime>) -> Self {
|
||||||
|
let mut tracing_dispatcher = None;
|
||||||
|
tracing::dispatcher::get_default(|what| tracing_dispatcher = Some(what.clone()));
|
||||||
|
PluginContainer {
|
||||||
|
function_map: Arc::new(Mutex::new(HashMap::new())),
|
||||||
|
libraries: Arc::new(Mutex::new(HashMap::new())),
|
||||||
|
reactor,
|
||||||
|
tracing_dispatcher: tracing_dispatcher.unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_plugin(&self, path: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let lib_name = path.to_string_lossy().to_string();
|
||||||
|
let lib = unsafe { Library::new(path) }?;
|
||||||
|
|
||||||
|
info!("loading plugin {path:?}");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let func: Symbol<unsafe extern "C" fn(Arc<Runtime>)> =
|
||||||
|
lib.get(b"register_reactor\0")?;
|
||||||
|
func(Arc::clone(&self.reactor));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let func: Symbol<unsafe extern "C" fn(&Dispatch)> =
|
||||||
|
lib.get(b"register_dispatcher\0")?;
|
||||||
|
func(&self.tracing_dispatcher.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let func: Symbol<unsafe extern "C" fn(Arc<Mutex<HashMap<String, AsyncFn>>>)> =
|
||||||
|
lib.get(b"register_functions\0")?;
|
||||||
|
func(Arc::clone(&self.function_map));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.libraries.lock().unwrap().insert(lib_name, lib);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unload_plugin(&self, path: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let lib_name = path.to_string_lossy().to_string();
|
||||||
|
let lib = self
|
||||||
|
.libraries
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.remove(&lib_name)
|
||||||
|
.ok_or("Library not loaded")?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let func: Symbol<unsafe extern "C" fn()> = lib.get(b"unregister_functions\0")?;
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#[tokio::main]
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
tracing::subscriber::set_global_default(
|
||||||
|
tracing_subscriber::fmt()
|
||||||
|
.with_max_level(tracing::Level::DEBUG)
|
||||||
|
.finish(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
info!("starting...");
|
||||||
|
|
||||||
|
let tokio_reactor = Arc::new(
|
||||||
|
::tokio::runtime::Builder::new_multi_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let plugin_manager = PluginContainer::new(tokio_reactor.clone());
|
||||||
|
|
||||||
|
let plugin_paths = vec![PathBuf::from("target/debug/libplugin_lib.so")]; // Adjust paths as needed
|
||||||
|
for path in plugin_paths {
|
||||||
|
if let Err(e) = plugin_manager.load_plugin(&path) {
|
||||||
|
eprintln!("Failed to load plugin from {:?}: {}", path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("plugins loaded...");
|
||||||
|
|
||||||
|
tokio_reactor.block_on(async {
|
||||||
|
loop {
|
||||||
|
let name = get_name().await;
|
||||||
|
if let Some(func) = plugin_manager.function_map.lock().unwrap().get(&name) {
|
||||||
|
info!("found func...");
|
||||||
|
|
||||||
|
let handle = func();
|
||||||
|
info!("obtained handle...");
|
||||||
|
task::spawn(async move {
|
||||||
|
info!("executing function...",);
|
||||||
|
match handle.await {
|
||||||
|
//Ok(()) => info!("Function {} executed successfully", name),
|
||||||
|
//Err(e) => error!("Function {} returned an error: {}", name, e),
|
||||||
|
Ok(Ok(())) => info!("Function {} executed successfully", name),
|
||||||
|
Ok(Err(e)) => error!("Function {} returned an error: {}", name, e),
|
||||||
|
Err(e) => error!("Task join error for function {}: {:?}", name, e),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//let handle = func();
|
||||||
|
////info!("obtained handle...");
|
||||||
|
////task::spawn(async move {
|
||||||
|
// info!("executing function...",);
|
||||||
|
// match handle.await {
|
||||||
|
// Ok(()) => info!("Function {} executed successfully", name),
|
||||||
|
// Err(e) => error!("Function {} returned an error: {}", name, e),
|
||||||
|
// //Err(e) => error!("Task join error for function {}: {:?}", name, e),
|
||||||
|
// }
|
||||||
|
////});
|
||||||
|
} else {
|
||||||
|
info!("Function not found for name: {}", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
|
||||||
|
if let Err(e) =
|
||||||
|
plugin_manager.unload_plugin(&PathBuf::from("target/debug/libplugin_lib.so"))
|
||||||
|
{
|
||||||
|
eprintln!("Failed to unload plugin: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_name() -> String {
|
||||||
|
"example_function".to_string()
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue