summaryrefslogtreecommitdiff
path: root/libs/all_in_one/src/ffi.rs
diff options
context:
space:
mode:
Diffstat (limited to 'libs/all_in_one/src/ffi.rs')
-rw-r--r--libs/all_in_one/src/ffi.rs143
1 files changed, 143 insertions, 0 deletions
diff --git a/libs/all_in_one/src/ffi.rs b/libs/all_in_one/src/ffi.rs
new file mode 100644
index 0000000..b4c853d
--- /dev/null
+++ b/libs/all_in_one/src/ffi.rs
@@ -0,0 +1,143 @@
+#![allow(clippy::missing_safety_doc)]
+use std::{
+ ffi::{c_char, c_int, CString},
+ mem::take,
+ ptr,
+ str::FromStr,
+ time::Duration,
+};
+
+use gateway::GatewayServer;
+use opentelemetry::{global::set_text_map_propagator, sdk::propagation::TraceContextPropagator};
+use ratelimit::RatelimiterServerComponent;
+use rest::ReverseProxyServer;
+use tokio::{runtime::Runtime, sync::mpsc};
+use tracing::{debug, error};
+use tracing_subscriber::{
+ filter::Directive, fmt, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt,
+ EnvFilter,
+};
+use webhook::WebhookServer;
+
+use crate::{
+ errors::{handle_error, wrap_result, ERROR_HANDLER},
+ utils::{load_config_file, start_component, AllInOneInstance},
+};
+
+#[no_mangle]
+pub unsafe extern "C" fn set_error_handler(func: unsafe extern "C" fn(c_int, *mut c_char)) {
+ debug!("Setting error handler");
+ ERROR_HANDLER.with(|prev| {
+ *prev.borrow_mut() = Some(func);
+ });
+}
+
+#[no_mangle]
+/// Loads the config json using the nova shared config loader
+pub extern "C" fn load_config() -> *mut c_char {
+ wrap_result(move || {
+ let config = serde_json::to_string(&load_config_file()?)?;
+ let c_str_song = CString::new(config)?;
+ Ok(c_str_song.into_raw())
+ })
+ .or(Some(ptr::null::<c_char>() as *mut c_char))
+ .expect("something has gone terribly wrong")
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn stop_instance(instance: *mut AllInOneInstance) {
+ wrap_result(move || {
+ let mut instance = Box::from_raw(instance);
+ let handles = take(&mut instance.handles);
+ instance.runtime.block_on(async move {
+ for (name, sender, join) in handles {
+ debug!("Halting component {}", name);
+ let _ = sender
+ .send(())
+ .map_err(|_| error!("Component {} is not online", name));
+ match join.await {
+ Ok(_) => {}
+ Err(error) => error!("Task for component {} panic'ed {}", name, error),
+ };
+ debug!("Component {} halted", name);
+ }
+ });
+
+ instance.runtime.shutdown_timeout(Duration::from_secs(5));
+
+ Ok(())
+ });
+}
+
+/// # Panics
+/// Panics if an incorrect `RUST_LOG` variables is specified.
+#[no_mangle]
+pub unsafe extern "C" fn create_instance(config: *mut c_char) -> *mut AllInOneInstance {
+ // Returning a null pointer (unaligned) is expected.
+ #[allow(clippy::cast_ptr_alignment)]
+ wrap_result(move || {
+ let value = CString::from_raw(config);
+ let json = value.to_str()?;
+
+ // Main stop signal for this instance
+ let (error_sender, mut errors) = mpsc::channel(50);
+ let mut handles = vec![];
+
+ let runtime = Runtime::new()?;
+
+ // Setup the tracing system
+ set_text_map_propagator(TraceContextPropagator::new());
+ tracing_subscriber::registry()
+ .with(fmt::layer())
+ .with(
+ EnvFilter::builder()
+ .with_default_directive(Directive::from_str("info").expect(""))
+ .from_env()
+ .unwrap(),
+ )
+ .init();
+
+ // Error handling task
+ runtime.spawn(async move {
+ while let Some(error) = errors.recv().await {
+ handle_error(&error);
+ }
+ });
+
+ handles.push(start_component::<GatewayServer>(
+ json,
+ error_sender.clone(),
+ &runtime,
+ )?);
+
+ std::thread::sleep(Duration::from_secs(1));
+
+ handles.push(start_component::<RatelimiterServerComponent>(
+ json,
+ error_sender.clone(),
+ &runtime,
+ )?);
+
+ std::thread::sleep(Duration::from_secs(1));
+
+ handles.push(start_component::<ReverseProxyServer>(
+ json,
+ error_sender.clone(),
+ &runtime,
+ )?);
+
+ std::thread::sleep(Duration::from_secs(1));
+
+ handles.push(start_component::<WebhookServer>(
+ json,
+ error_sender,
+ &runtime,
+ )?);
+
+ let all_in_one = Box::into_raw(Box::new(AllInOneInstance { runtime, handles }));
+
+ Ok(all_in_one)
+ })
+ .or(Some(ptr::null::<AllInOneInstance>() as *mut AllInOneInstance))
+ .expect("something has gone terribly wrong")
+}