Files
continuwuity/src/core/server.rs
T

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

153 lines
3.8 KiB
Rust
Raw Normal View History

2024-05-09 15:59:08 -07:00
use std::{
2024-12-29 02:21:22 +00:00
sync::{
Arc,
atomic::{AtomicBool, Ordering},
2024-12-29 02:21:22 +00:00
},
2024-05-09 15:59:08 -07:00
time::SystemTime,
};
2025-01-25 23:41:39 +00:00
use ruma::OwnedServerName;
2024-06-01 08:03:20 +00:00
use tokio::{runtime, sync::broadcast};
2024-05-09 15:59:08 -07:00
use crate::{Err, Result, config, config::Config, log::Log, metrics::Metrics};
2024-05-09 15:59:08 -07:00
/// Server runtime state; public portion
pub struct Server {
2025-01-25 23:41:39 +00:00
/// Configured name of server. This is the same as the one in the config
/// but developers can (and should) reference this string instead.
pub name: OwnedServerName,
2024-05-09 15:59:08 -07:00
/// Server-wide configuration instance
2025-01-24 07:04:29 +00:00
pub config: config::Manager,
2024-05-09 15:59:08 -07:00
/// Timestamp server was started; used for uptime.
pub started: SystemTime,
/// Reload/shutdown pending indicator; server is shutting down. This is an
/// observable used on shutdown and should not be modified.
pub stopping: AtomicBool,
2024-06-01 08:03:20 +00:00
2024-05-09 15:59:08 -07:00
/// Reload/shutdown desired indicator; when false, shutdown is desired. This
/// is an observable used on shutdown and modifying is not recommended.
pub reloading: AtomicBool,
2024-05-09 15:59:08 -07:00
2024-06-16 19:46:32 +00:00
/// Restart desired; when true, restart it desired after shutdown.
pub restarting: AtomicBool,
2024-05-09 15:59:08 -07:00
/// Handle to the runtime
pub runtime: Option<runtime::Handle>,
/// Reload/shutdown signal
pub signal: broadcast::Sender<&'static str>,
2024-06-11 01:26:31 +00:00
/// Logging subsystem state
2024-06-25 05:05:02 +00:00
pub log: Log,
2024-05-09 15:59:08 -07:00
2024-06-25 05:05:02 +00:00
/// Metrics subsystem state
pub metrics: Metrics,
2024-05-09 15:59:08 -07:00
}
impl Server {
#[must_use]
2024-06-25 05:05:02 +00:00
pub fn new(config: Config, runtime: Option<runtime::Handle>, log: Log) -> Self {
2024-05-09 15:59:08 -07:00
Self {
2025-01-25 23:41:39 +00:00
name: config.server_name.clone(),
2025-01-24 07:04:29 +00:00
config: config::Manager::new(config),
2024-05-09 15:59:08 -07:00
started: SystemTime::now(),
stopping: AtomicBool::new(false),
reloading: AtomicBool::new(false),
2024-06-16 19:46:32 +00:00
restarting: AtomicBool::new(false),
2024-06-25 05:05:02 +00:00
runtime: runtime.clone(),
signal: broadcast::channel::<&'static str>(1).0,
2024-06-11 01:26:31 +00:00
log,
2024-06-25 05:05:02 +00:00
metrics: Metrics::new(runtime),
2024-05-09 15:59:08 -07:00
}
}
2024-06-16 01:39:14 +00:00
pub fn reload(&self) -> Result<()> {
if cfg!(any(not(conduwuit_mods), not(feature = "conduwuit_mods"))) {
return Err!("Reloading not enabled");
2024-06-16 01:39:14 +00:00
}
if self.reloading.swap(true, Ordering::AcqRel) {
return Err!("Reloading already in progress");
2024-06-16 01:39:14 +00:00
}
if self.stopping.swap(true, Ordering::AcqRel) {
return Err!("Shutdown already in progress");
2024-06-16 01:39:14 +00:00
}
2024-07-06 13:53:21 +00:00
self.signal("SIGINT").inspect_err(|_| {
self.stopping.store(false, Ordering::Release);
self.reloading.store(false, Ordering::Release);
})
2024-06-16 01:39:14 +00:00
}
pub fn restart(&self) -> Result {
2024-06-16 19:46:32 +00:00
if self.restarting.swap(true, Ordering::AcqRel) {
return Err!("Restart already in progress");
2024-06-16 19:46:32 +00:00
}
self.shutdown().inspect_err(|_| {
self.restarting.store(false, Ordering::Release);
})
2024-06-16 19:46:32 +00:00
}
pub fn shutdown(&self) -> Result {
2024-06-16 01:39:14 +00:00
if self.stopping.swap(true, Ordering::AcqRel) {
return Err!("Shutdown already in progress");
2024-06-16 01:39:14 +00:00
}
self.signal("SIGTERM").inspect_err(|_| {
self.stopping.store(false, Ordering::Release);
})
2024-06-16 01:39:14 +00:00
}
pub fn signal(&self, sig: &'static str) -> Result<()> {
if let Err(e) = self.signal.send(sig) {
return Err!("Failed to send signal: {e}");
2024-06-16 01:39:14 +00:00
}
Ok(())
}
2024-12-29 02:21:22 +00:00
#[inline]
2025-01-28 20:02:29 +00:00
pub async fn until_shutdown(self: &Arc<Self>) {
2024-12-29 02:21:22 +00:00
while self.running() {
self.signal.subscribe().recv().await.ok();
}
}
2024-05-09 15:59:08 -07:00
#[inline]
pub fn runtime(&self) -> &runtime::Handle {
self.runtime
.as_ref()
.expect("runtime handle available in Server")
}
2024-06-05 21:57:10 +00:00
#[inline]
pub fn check_running(&self) -> Result {
use std::{io, io::ErrorKind::Interrupted};
self.running()
.then_some(())
.ok_or_else(|| io::Error::new(Interrupted, "Server shutting down"))
.map_err(Into::into)
}
2024-06-05 21:57:10 +00:00
#[inline]
2025-04-02 04:12:24 +00:00
pub fn running(&self) -> bool { !self.is_stopping() }
#[inline]
pub fn is_stopping(&self) -> bool { self.stopping.load(Ordering::Relaxed) }
#[inline]
pub fn is_reloading(&self) -> bool { self.reloading.load(Ordering::Relaxed) }
#[inline]
pub fn is_restarting(&self) -> bool { self.restarting.load(Ordering::Relaxed) }
2024-07-22 07:43:51 +00:00
#[inline]
pub fn is_ours(&self, name: &str) -> bool { name == self.config.server_name }
2024-05-09 15:59:08 -07:00
}