de-global services

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2024-07-27 07:17:07 +00:00
parent 7e50db4193
commit 2f85a5c1ac
36 changed files with 327 additions and 336 deletions

View file

@ -9,7 +9,7 @@ use std::{
};
use async_trait::async_trait;
use conduit::{debug, error, error::default_log, pdu::PduBuilder, Error, PduEvent, Result, Server};
use conduit::{debug, error, error::default_log, pdu::PduBuilder, Err, Error, PduEvent, Result, Server};
pub use create::create_admin_room;
use loole::{Receiver, Sender};
use ruma::{
@ -41,6 +41,7 @@ struct Services {
timeline: Dep<rooms::timeline::Service>,
state: Dep<rooms::state::Service>,
state_cache: Dep<rooms::state_cache::Service>,
services: StdRwLock<Option<Arc<crate::Services>>>,
}
#[derive(Debug)]
@ -50,7 +51,7 @@ pub struct CommandInput {
}
pub type Completer = fn(&str) -> String;
pub type Handler = fn(CommandInput) -> HandlerResult;
pub type Handler = fn(Arc<crate::Services>, CommandInput) -> HandlerResult;
pub type HandlerResult = Pin<Box<dyn Future<Output = CommandResult> + Send>>;
pub type CommandResult = Result<CommandOutput, Error>;
pub type CommandOutput = Option<RoomMessageEventContent>;
@ -69,6 +70,7 @@ impl crate::Service for Service {
timeline: args.depend::<rooms::timeline::Service>("rooms::timeline"),
state: args.depend::<rooms::state::Service>("rooms::state"),
state_cache: args.depend::<rooms::state_cache::Service>("rooms::state_cache"),
services: None.into(),
},
sender,
receiver: Mutex::new(receiver),
@ -172,10 +174,14 @@ impl Service {
}
async fn process_command(&self, command: CommandInput) -> CommandResult {
let Some(services) = self.services.services.read().expect("locked").clone() else {
return Err!("Services self-reference not initialized.");
};
if let Some(handle) = self.handle.read().await.as_ref() {
handle(command).await
handle(services, command).await
} else {
Err(Error::Err("Admin module is not loaded.".into()))
Err!("Admin module is not loaded.")
}
}
@ -356,4 +362,10 @@ impl Service {
#[cfg(feature = "console")]
self.console.close().await;
}
/// Sets the self-reference to crate::Services which will provide context to
/// the admin commands.
pub(super) fn set_services(&self, services: Option<Arc<crate::Services>>) {
*self.services.services.write().expect("locked for writing") = services;
}
}

View file

@ -1,4 +1,4 @@
#![recursion_limit = "160"]
#![recursion_limit = "192"]
#![allow(refining_impl_trait)]
mod manager;
@ -26,11 +26,7 @@ pub mod users;
extern crate conduit_core as conduit;
extern crate conduit_database as database;
use std::sync::{Arc, RwLock};
pub use conduit::{pdu, PduBuilder, PduCount, PduEvent};
use conduit::{Result, Server};
use database::Database;
pub(crate) use service::{Args, Dep, Service};
pub use crate::services::Services;
@ -38,50 +34,3 @@ pub use crate::services::Services;
conduit::mod_ctor! {}
conduit::mod_dtor! {}
conduit::rustc_flags_capture! {}
static SERVICES: RwLock<Option<&Services>> = RwLock::new(None);
pub async fn start(server: &Arc<Server>) -> Result<()> {
let d = Arc::new(Database::open(server).await?);
let s = Box::new(Services::build(server.clone(), d)?);
_ = SERVICES.write().expect("write locked").insert(Box::leak(s));
services().start().await
}
pub async fn stop() {
services().stop().await;
// Deactivate services(). Any further use will panic the caller.
let s = SERVICES
.write()
.expect("write locked")
.take()
.expect("services initialized");
let s: *mut Services = std::ptr::from_ref(s).cast_mut();
//SAFETY: Services was instantiated in init() and leaked into the SERVICES
// global perusing as 'static for the duration of service. Now we reclaim
// it to drop it before unloading the module. If this is not done there wil
// be multiple instances after module reload.
let s = unsafe { Box::from_raw(s) };
// Drop it so we encounter any trouble before the infolog message
drop(s);
}
#[must_use]
pub fn services() -> &'static Services {
SERVICES
.read()
.expect("SERVICES locked for reading")
.expect("SERVICES initialized with Services instance")
}
#[inline]
pub fn available() -> bool {
SERVICES
.read()
.expect("SERVICES locked for reading")
.is_some()
}

View file

@ -44,7 +44,8 @@ pub struct Services {
impl Services {
#[allow(clippy::cognitive_complexity)]
pub fn build(server: Arc<Server>, db: Arc<Database>) -> Result<Self> {
pub async fn build(server: Arc<Server>) -> Result<Arc<Self>> {
let db = Database::open(&server).await?;
let service: Arc<Map> = Arc::new(RwLock::new(BTreeMap::new()));
macro_rules! build {
($tyname:ty) => {{
@ -58,7 +59,7 @@ impl Services {
}};
}
Ok(Self {
Ok(Arc::new(Self {
account_data: build!(account_data::Service),
admin: build!(admin::Service),
appservice: build!(appservice::Service),
@ -102,12 +103,13 @@ impl Services {
service,
server,
db,
})
}))
}
pub(super) async fn start(&self) -> Result<()> {
pub async fn start(self: &Arc<Self>) -> Result<Arc<Self>> {
debug_info!("Starting services...");
self.admin.set_services(Some(Arc::clone(self)));
globals::migrations::migrations(self).await?;
self.manager
.lock()
@ -118,10 +120,10 @@ impl Services {
.await?;
debug_info!("Services startup complete.");
Ok(())
Ok(Arc::clone(self))
}
pub(super) async fn stop(&self) {
pub async fn stop(&self) {
info!("Shutting down services...");
self.interrupt();
@ -129,6 +131,8 @@ impl Services {
manager.stop().await;
}
self.admin.set_services(None);
debug_info!("Services shutdown complete.");
}