Merge branch 'main' into feature/apub-inbox
# Conflicts: # .idea/acrate.iml # Cargo.toml # acrate_rdserver/src/config.rs # acrate_rdserver/src/main.rs
This commit is contained in:
commit
72f12b6de7
12 changed files with 192 additions and 42 deletions
|
@ -15,6 +15,7 @@
|
||||||
<sourceFolder url="file://$MODULE_DIR$/acrate_database/tests" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/acrate_database/tests" isTestSource="true" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/acrate_astreams/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/acrate_astreams/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/acrate_astreams/tests" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/acrate_astreams/tests" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/acrate_utils/src" isTestSource="false" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|
20
.idea/runConfigurations/Doc.xml
Normal file
20
.idea/runConfigurations/Doc.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Doc" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||||
|
<option name="buildProfileId" value="dev" />
|
||||||
|
<option name="command" value="doc" />
|
||||||
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
|
<envs />
|
||||||
|
<option name="emulateTerminal" value="true" />
|
||||||
|
<option name="channel" value="DEFAULT" />
|
||||||
|
<option name="requiredFeatures" value="true" />
|
||||||
|
<option name="allFeatures" value="false" />
|
||||||
|
<option name="withSudo" value="false" />
|
||||||
|
<option name="buildTarget" value="REMOTE" />
|
||||||
|
<option name="backtrace" value="SHORT" />
|
||||||
|
<option name="isRedirectInput" value="false" />
|
||||||
|
<option name="redirectInputPath" value="" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
|
@ -1,3 +1,3 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = ["acrate_database", "acrate_rd", "acrate_nodeinfo", "acrate_rdserver", "acrate_apub_inbox", "acrate_astreams"]
|
members = ["acrate_database", "acrate_rd", "acrate_nodeinfo", "acrate_rdserver", "acrate_apub_inbox", "acrate_astreams", "acrate_utils"]
|
||||||
|
|
|
@ -12,12 +12,12 @@ categories = ["web-programming"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
acrate_database = { path = "../acrate_database", features = ["connect"] }
|
acrate_database = { path = "../acrate_database", features = ["connect"] }
|
||||||
acrate_rd = { path = "../acrate_rd" }
|
acrate_rd = { path = "../acrate_rd" }
|
||||||
|
acrate_utils = { path = "../acrate_utils" }
|
||||||
anyhow = "1.0.93"
|
anyhow = "1.0.93"
|
||||||
axum = { version = "0.7.7", features = ["macros"] }
|
axum = { version = "0.7.7", features = ["macros"] }
|
||||||
axum-extra = { version = "0.9.4", features = ["query"] }
|
axum-extra = { version = "0.9.4", features = ["query"] }
|
||||||
log = { version = "0.4.22", features = ["std", "max_level_trace", "release_max_level_debug"] }
|
log = { version = "0.4.22", features = ["std", "max_level_trace", "release_max_level_debug"] }
|
||||||
micronfig = "0.3.0"
|
micronfig = "0.3.0"
|
||||||
minijinja = "2.5.0"
|
|
||||||
pretty_env_logger = "0.5.0"
|
pretty_env_logger = "0.5.0"
|
||||||
quick-xml = { version = "0.37.0", features = ["serialize"] }
|
quick-xml = { version = "0.37.0", features = ["serialize"] }
|
||||||
serde = { version = "1.0.215", features = ["derive"] }
|
serde = { version = "1.0.215", features = ["derive"] }
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
micronfig::config!(
|
micronfig::config!(
|
||||||
ACRATE_RDSERVER_BIND_ADDRESS: String,
|
ACRATE_RDSERVER_BIND_ADDRESS: String > std::net::SocketAddr,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,42 +1,19 @@
|
||||||
use std::sync::Arc;
|
use axum::routing::get;
|
||||||
use anyhow::Context;
|
use acrate_utils::web_server;
|
||||||
use axum::Extension;
|
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod route;
|
mod route;
|
||||||
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<std::convert::Infallible> {
|
async fn main() {
|
||||||
pretty_env_logger::init();
|
web_server!(
|
||||||
log::debug!("Logging initialized!");
|
on: *config::ACRATE_RDSERVER_BIND_ADDRESS(),
|
||||||
|
templates: [
|
||||||
log::trace!("Creating Minijinja environment...");
|
"rd.html.j2"
|
||||||
let mut mj = minijinja::Environment::<'static>::new();
|
],
|
||||||
|
routes: {
|
||||||
log::trace!("Adding webfinger page to the Minijinja environment...");
|
"/*path" => get(route::webfinger_handler),
|
||||||
mj.add_template("rd.html.j2", include_str!("rd.html.j2"))
|
"/.healthcheck" => get(route::healthcheck_handler)
|
||||||
.expect("rd.html.j2 to be a valid Minijinja template");
|
}
|
||||||
|
);
|
||||||
log::trace!("Creating Axum router...");
|
|
||||||
let app = axum::Router::new()
|
|
||||||
.route("/*path", axum::routing::get(route::webfinger_handler))
|
|
||||||
.route("/.healthcheck", axum::routing::get(route::healthcheck_handler))
|
|
||||||
.layer(Extension(Arc::new(mj)));
|
|
||||||
log::trace!("Axum router created successfully!");
|
|
||||||
|
|
||||||
log::trace!("Creating Tokio listener...");
|
|
||||||
let bind_address = config::ACRATE_RDSERVER_BIND_ADDRESS();
|
|
||||||
let listener = tokio::net::TcpListener::bind(bind_address)
|
|
||||||
.await
|
|
||||||
.context("failed to bind listener to address")?;
|
|
||||||
log::trace!("Tokio listener bound to: {bind_address}");
|
|
||||||
|
|
||||||
log::info!("Starting rdserver web server...");
|
|
||||||
axum::serve(listener, app)
|
|
||||||
.await
|
|
||||||
.context("server exited with error")?;
|
|
||||||
|
|
||||||
log::error!("Server exited with no error, panicking.");
|
|
||||||
panic!("server exited with no error");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::iter::IntoIterator;
|
use std::iter::IntoIterator;
|
||||||
use std::sync::Arc;
|
|
||||||
use axum::Extension;
|
use axum::Extension;
|
||||||
use axum::extract::Path;
|
use axum::extract::Path;
|
||||||
use axum::http::{HeaderMap, Response, StatusCode};
|
use axum::http::{HeaderMap, Response, StatusCode};
|
||||||
|
@ -11,6 +10,7 @@ use acrate_database::diesel::GroupedBy;
|
||||||
use acrate_database::meta::{MetaAlias, MetaLink, MetaLinkProperty, MetaLinkTitle, MetaProperty, MetaSubject};
|
use acrate_database::meta::{MetaAlias, MetaLink, MetaLinkProperty, MetaLinkTitle, MetaProperty, MetaSubject};
|
||||||
use acrate_rd::jrd::ResourceDescriptorLinkJRD;
|
use acrate_rd::jrd::ResourceDescriptorLinkJRD;
|
||||||
use acrate_rd::xrd::{ResourceDescriptorLinkXRD, ResourceDescriptorPropertyXRD, ResourceDescriptorTitleXRD};
|
use acrate_rd::xrd::{ResourceDescriptorLinkXRD, ResourceDescriptorPropertyXRD, ResourceDescriptorTitleXRD};
|
||||||
|
use acrate_utils::ext::{minijinja, ExtMj};
|
||||||
|
|
||||||
pub async fn healthcheck_handler() -> Result<StatusCode, StatusCode> {
|
pub async fn healthcheck_handler() -> Result<StatusCode, StatusCode> {
|
||||||
log::debug!("Handling an healthcheck request!");
|
log::debug!("Handling an healthcheck request!");
|
||||||
|
@ -36,7 +36,7 @@ pub async fn webfinger_handler(
|
||||||
Path(path): Path<String>,
|
Path(path): Path<String>,
|
||||||
Query(WebfingerQuery {resource, rel}): Query<WebfingerQuery>,
|
Query(WebfingerQuery {resource, rel}): Query<WebfingerQuery>,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
Extension(mj): Extension<Arc<minijinja::Environment<'static>>>,
|
Extension(mj): ExtMj,
|
||||||
) -> Result<Response<String>, StatusCode> {
|
) -> Result<Response<String>, StatusCode> {
|
||||||
log::debug!("Handling a WebFinger request!");
|
log::debug!("Handling a WebFinger request!");
|
||||||
|
|
||||||
|
|
22
acrate_utils/Cargo.toml
Normal file
22
acrate_utils/Cargo.toml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
[package]
|
||||||
|
name = "acrate_utils"
|
||||||
|
version = "0.3.0"
|
||||||
|
authors = ["Stefano Pigozzi <me@steffo.eu>"]
|
||||||
|
edition = "2021"
|
||||||
|
description = "Utilities for the acrate project"
|
||||||
|
repository = "https://forge.steffo.eu/unimore/tirocinio-canali-steffo-acrate"
|
||||||
|
license = "EUPL-1.2"
|
||||||
|
keywords = []
|
||||||
|
categories = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
axum = { version = "0.7.7", features = ["macros"] }
|
||||||
|
axum-extra = { version = "0.9.4", features = ["query"] }
|
||||||
|
log = { version = "0.4.22", features = ["std", "max_level_trace", "release_max_level_debug"] }
|
||||||
|
pretty_env_logger = "0.5.0"
|
||||||
|
mediatype = { version = "0.19.18", features = ["serde"] }
|
||||||
|
minijinja = "2.5.0"
|
||||||
|
tokio = { version = "1.41.1", features = ["net"] }
|
||||||
|
|
||||||
|
[lints.clippy]
|
||||||
|
tabs-in-doc-comments = "allow"
|
6
acrate_utils/src/ext.rs
Normal file
6
acrate_utils/src/ext.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
use axum::Extension;
|
||||||
|
|
||||||
|
pub use minijinja;
|
||||||
|
|
||||||
|
pub type ExtMj = Extension<Arc<minijinja::Environment<'static>>>;
|
49
acrate_utils/src/init.rs
Normal file
49
acrate_utils/src/init.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use axum::Extension;
|
||||||
|
|
||||||
|
/// Initialize logging with [`pretty_env_logger::init`].
|
||||||
|
pub fn init_logging() {
|
||||||
|
log::trace!("Initializing logging...");
|
||||||
|
pretty_env_logger::init();
|
||||||
|
log::trace!("Initialized logging!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a [`tokio::net::TcpListener`] bound to the given [`SocketAddr`].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If unable to bind to the given [`SocketAddr`].
|
||||||
|
///
|
||||||
|
pub async fn init_listener(bind: SocketAddr) -> tokio::net::TcpListener {
|
||||||
|
log::trace!("Creating Tokio listener bound to: {bind:#?}");
|
||||||
|
let listener = tokio::net::TcpListener::bind(bind)
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to bind to: {bind:#?}"));
|
||||||
|
log::trace!("Created Tokio listener: {listener:#?}");
|
||||||
|
|
||||||
|
listener
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a static [`minijinja::Environment`].
|
||||||
|
pub fn init_minijinja() -> minijinja::Environment<'static> {
|
||||||
|
log::trace!("Creating Minijinja environment...");
|
||||||
|
let mj = minijinja::Environment::<'static>::new();
|
||||||
|
log::trace!("Created Minijinja environment: {mj:#?}");
|
||||||
|
|
||||||
|
mj
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize an [`axum::Router`] with the given [`minijinja::Environment`] available.
|
||||||
|
pub fn init_router(mj: minijinja::Environment<'static>) -> axum::Router {
|
||||||
|
log::trace!("Creating Arc for the minijinja Environment...");
|
||||||
|
let mj = Arc::new(mj);
|
||||||
|
log::trace!("Created Arc for the minijinja Environment: {mj:#?}");
|
||||||
|
|
||||||
|
log::trace!("Creating Axum router...");
|
||||||
|
let router = axum::Router::new()
|
||||||
|
.layer(Extension(mj));
|
||||||
|
log::trace!("Created Axum router: {router:#?}");
|
||||||
|
|
||||||
|
router
|
||||||
|
}
|
50
acrate_utils/src/lib.rs
Normal file
50
acrate_utils/src/lib.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
pub mod ext;
|
||||||
|
pub mod init;
|
||||||
|
pub mod run;
|
||||||
|
|
||||||
|
|
||||||
|
/// Add the template file at the given path to the given [`minijinja::Environment`].
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! add_minijinja_template {
|
||||||
|
($mj:ident, $path:literal) => {
|
||||||
|
log::trace!("Adding template to minijinja Environment: {:?} ← {:#?}", $mj, $path);
|
||||||
|
$mj.add_template($path, include_str!($path))
|
||||||
|
.expect(concat!("Invalid Minijinja template: ", $path));
|
||||||
|
log::trace!("Added template to minijinja Environment: {:?} ← {:#?}", $mj, $path);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add the given route to the [`axum::Router`].
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! add_axum_route {
|
||||||
|
($router:ident, $path:literal, $route:expr) => {
|
||||||
|
log::trace!("Adding route to axum Router: {:?} ← {:#?}", $router, $path);
|
||||||
|
let $router = $router.route($path, $route);
|
||||||
|
log::trace!("Added route to axum Router: {:?} ← {:#?}", $router, $path);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! web_server {
|
||||||
|
(
|
||||||
|
on: $socket_addr:expr,
|
||||||
|
templates: [
|
||||||
|
$( $template_path:literal ),+
|
||||||
|
],
|
||||||
|
routes: {
|
||||||
|
$( $path:literal => $route:expr ),+
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
$crate::init::init_logging();
|
||||||
|
let listener = $crate::init::init_listener($socket_addr).await;
|
||||||
|
let mut mj = $crate::init::init_minijinja();
|
||||||
|
$(
|
||||||
|
$crate::add_minijinja_template!(mj, $template_path);
|
||||||
|
)+
|
||||||
|
let router = $crate::init::init_router(mj);
|
||||||
|
$(
|
||||||
|
$crate::add_axum_route!(router, $path, $route);
|
||||||
|
)+
|
||||||
|
$crate::run::run_server(listener, router).await
|
||||||
|
};
|
||||||
|
}
|
25
acrate_utils/src/run.rs
Normal file
25
acrate_utils/src/run.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/// Run a web server with [`axum::serve`], using the given [`tokio::net::TcpListener`] and [`axum::Router`].
|
||||||
|
///
|
||||||
|
/// # Exits
|
||||||
|
///
|
||||||
|
/// Once the server is terminated, the process will exit with either:
|
||||||
|
///
|
||||||
|
/// - `0`, if [`axum::serve`] returned [`Ok`];
|
||||||
|
/// - `1`, if [`axum::serve`] returned [`Err`].
|
||||||
|
///
|
||||||
|
pub async fn run_server(listener: tokio::net::TcpListener, application: axum::Router) -> std::convert::Infallible {
|
||||||
|
log::trace!("Serving application: {listener:#?} → {application:#?}");
|
||||||
|
let result = axum::serve(listener, application)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(()) => {
|
||||||
|
log::error!("Server exited gracefully.");
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Server exited with an error: {e:#?}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue