// Avoid spurious warnings with --no-default-features, which isn't expected to // work anyway #![cfg_attr(not(any(feature = "sqlite", feature = "rocksdb")), allow(unused))] use std::process::ExitCode; use clap::Parser; use tracing::{error, info}; mod api; mod cli; mod config; mod database; mod error; mod observability; mod service; mod utils; pub(crate) use api::ruma_wrapper::{Ar, Ra}; pub(crate) use config::Config; pub(crate) use service::{pdu::PduEvent, services, Services}; #[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))] use tikv_jemallocator::Jemalloc; pub(crate) use utils::error::{Error, Result}; #[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))] #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; /// Returns the current version of the crate with extra info if supplied /// /// Set the environment variable `GRAPEVINE_VERSION_EXTRA` to any UTF-8 string /// to include it in parenthesis after the SemVer version. A common value are /// git commit hashes. fn version() -> String { let cargo_pkg_version = env!("CARGO_PKG_VERSION"); match option_env!("GRAPEVINE_VERSION_EXTRA") { Some(x) => format!("{cargo_pkg_version} ({x})"), None => cargo_pkg_version.to_owned(), } } #[derive(Debug, Clone, Copy)] enum ApplicationState { Ready, Reloading, Stopping, } fn set_application_state(state: ApplicationState) { info!(?state, "Application state changed"); #[cfg(feature = "systemd")] { use sd_notify::NotifyState; fn notify(states: &[NotifyState<'_>]) { sd_notify::notify(false, states) .expect("should be able to notify systemd"); } match state { ApplicationState::Ready => notify(&[NotifyState::Ready]), ApplicationState::Reloading => { let timespec = nix::time::clock_gettime( nix::time::ClockId::CLOCK_MONOTONIC, ) .expect("CLOCK_MONOTONIC should be usable"); let monotonic_usec = timespec.tv_sec() * 1_000_000 + timespec.tv_nsec() / 1000; notify(&[ NotifyState::Reloading, NotifyState::Custom(&format!( "MONOTONIC_USEC={monotonic_usec}", )), ]); } ApplicationState::Stopping => notify(&[NotifyState::Stopping]), }; } } #[tokio::main] async fn main() -> ExitCode { let args = cli::Args::parse(); let Err(e) = args.run().await else { return ExitCode::SUCCESS; }; eprintln!( "Error: {}", error::DisplayWithSources { error: &e, infix: "\n Caused by: " } ); ExitCode::FAILURE }