Files
continuwuity/src/main/mods.rs
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

161 lines
3.7 KiB
Rust
Raw Normal View History

#![cfg(all(conduwuit_mods, feature = "conduwuit_mods"))]
2024-05-09 15:59:08 -07:00
#[unsafe(no_link)]
2024-12-14 21:58:01 -05:00
extern crate conduwuit_service;
2024-07-28 11:14:10 +00:00
2024-05-09 15:59:08 -07:00
use std::{
future::Future,
pin::Pin,
sync::{Arc, atomic::Ordering},
2024-05-09 15:59:08 -07:00
};
use conduwuit_core::{Error, Result, debug, error, mods};
2024-12-14 21:58:01 -05:00
use conduwuit_service::Services;
2024-05-09 15:59:08 -07:00
use crate::Server;
2024-07-28 11:14:10 +00:00
type StartFuncResult = Pin<Box<dyn Future<Output = Result<Arc<Services>>> + Send>>;
type StartFuncProto = fn(&Arc<conduwuit_core::Server>) -> StartFuncResult;
2024-07-28 11:14:10 +00:00
type RunFuncResult = Pin<Box<dyn Future<Output = Result<()>> + Send>>;
type RunFuncProto = fn(&Arc<Services>) -> RunFuncResult;
type StopFuncResult = Pin<Box<dyn Future<Output = Result<()>> + Send>>;
type StopFuncProto = fn(Arc<Services>) -> StopFuncResult;
2024-05-09 15:59:08 -07:00
2024-12-14 21:58:01 -05:00
const RESTART_THRESH: &str = "conduwuit_service";
2024-05-09 15:59:08 -07:00
const MODULE_NAMES: &[&str] = &[
2024-12-14 21:58:01 -05:00
//"conduwuit_core",
"conduwuit_database",
"conduwuit_service",
"conduwuit_api",
"conduwuit_admin",
"conduwuit_router",
2024-05-09 15:59:08 -07:00
];
#[cfg(panic_trap)]
conduwuit_core::mod_init! {{
conduwuit_core::debug::set_panic_trap();
2024-05-09 15:59:08 -07:00
}}
pub(crate) async fn run(server: &Arc<Server>, starts: bool) -> Result<(bool, bool), Error> {
let main_lock = server.mods.read().await;
let main_mod = (*main_lock).last().expect("main module loaded");
if starts {
2024-07-28 11:14:10 +00:00
let start = main_mod.get::<StartFuncProto>("start")?;
match start(&server.server).await {
| Ok(services) => server.services.lock().await.insert(services),
| Err(error) => {
2024-07-28 11:14:10 +00:00
error!("Starting server: {error}");
return Err(error);
},
};
2024-05-09 15:59:08 -07:00
}
2024-06-16 01:39:14 +00:00
server.server.stopping.store(false, Ordering::Release);
2024-05-09 15:59:08 -07:00
let run = main_mod.get::<RunFuncProto>("run")?;
2024-07-28 11:14:10 +00:00
if let Err(error) = run(server
.services
.lock()
.await
.as_ref()
.expect("services initialized"))
.await
{
2024-05-09 15:59:08 -07:00
error!("Running server: {error}");
return Err(error);
}
let reloads = server.server.reloading.swap(false, Ordering::AcqRel);
2024-05-09 15:59:08 -07:00
let stops = !reloads || stale(server).await? <= restart_thresh();
let starts = reloads && stops;
if stops {
2024-07-28 11:14:10 +00:00
let stop = main_mod.get::<StopFuncProto>("stop")?;
if let Err(error) = stop(
server
.services
.lock()
.await
.take()
.expect("services initialized"),
)
.await
{
2024-05-09 15:59:08 -07:00
error!("Stopping server: {error}");
return Err(error);
}
}
Ok((starts, reloads))
}
pub(crate) async fn open(server: &Arc<Server>) -> Result<usize, Error> {
let mut mods_lock = server.mods.write().await;
let mods: &mut Vec<mods::Module> = &mut mods_lock;
debug!(
available = %available(),
loaded = %mods.len(),
"Loading modules",
);
for (i, name) in MODULE_NAMES.iter().enumerate() {
if mods.get(i).is_none() {
mods.push(mods::Module::from_name(name)?);
}
}
Ok(mods.len())
}
pub(crate) async fn close(server: &Arc<Server>, force: bool) -> Result<usize, Error> {
let stale = stale_count(server).await;
let mut mods_lock = server.mods.write().await;
let mods: &mut Vec<mods::Module> = &mut mods_lock;
debug!(
available = %available(),
loaded = %mods.len(),
stale = %stale,
force,
"Unloading modules",
);
while mods.last().is_some() {
let module = &mods.last().expect("module");
if force || module.deleted()? {
mods.pop();
} else {
break;
}
}
Ok(mods.len())
}
async fn stale_count(server: &Arc<Server>) -> usize {
let watermark = stale(server).await.unwrap_or(available());
2024-07-28 11:14:10 +00:00
available().saturating_sub(watermark)
2024-05-09 15:59:08 -07:00
}
async fn stale(server: &Arc<Server>) -> Result<usize, Error> {
let mods_lock = server.mods.read().await;
let mods: &Vec<mods::Module> = &mods_lock;
for (i, module) in mods.iter().enumerate() {
if module.deleted()? {
return Ok(i);
}
}
Ok(mods.len())
}
fn restart_thresh() -> usize {
MODULE_NAMES
.iter()
.position(|&name| name.ends_with(RESTART_THRESH))
.unwrap_or(MODULE_NAMES.len())
}
const fn available() -> usize { MODULE_NAMES.len() }