mirror of
https://github.com/aljazceru/pubky-core.git
synced 2026-01-31 11:54:19 +01:00
feat(homeserver): basic Axum server with nothing but / router
This commit is contained in:
1010
Cargo.lock
generated
Normal file
1010
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
[workspace]
|
||||
members = []
|
||||
members = ["homeserver"]
|
||||
|
||||
# See: https://github.com/rust-lang/rust/issues/90148#issuecomment-949194352
|
||||
resolver = "2"
|
||||
|
||||
12
homeserver/Cargo.toml
Normal file
12
homeserver/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "pubky_homeserver"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.82"
|
||||
axum = "0.7.5"
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
tower-http = { version = "0.5.2", features = ["cors", "trace"] }
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||
4
homeserver/src/lib.rs
Normal file
4
homeserver/src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
mod routes;
|
||||
mod server;
|
||||
|
||||
pub use server::Homeserver;
|
||||
13
homeserver/src/main.rs
Normal file
13
homeserver/src/main.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use anyhow::Result;
|
||||
use pubky_homeserver::Homeserver;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
tracing_subscriber::fmt().init();
|
||||
|
||||
let server = Homeserver::start().await?;
|
||||
|
||||
server.run_until_done().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
7
homeserver/src/routes.rs
Normal file
7
homeserver/src/routes.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
use axum::{routing::get, Router};
|
||||
|
||||
pub mod root;
|
||||
|
||||
pub fn create_app() -> Router {
|
||||
Router::new().route("/", get(root::handler))
|
||||
}
|
||||
5
homeserver/src/routes/root.rs
Normal file
5
homeserver/src/routes/root.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
use axum::response::IntoResponse;
|
||||
|
||||
pub async fn handler() -> Result<impl IntoResponse, String> {
|
||||
Ok("This a Pubky homeserver.".to_string())
|
||||
}
|
||||
101
homeserver/src/server.rs
Normal file
101
homeserver/src/server.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
use std::{future::IntoFuture, net::SocketAddr};
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
use tokio::{net::TcpListener, signal, task::JoinSet};
|
||||
use tracing::{info, warn};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Homeserver {
|
||||
tasks: JoinSet<std::io::Result<()>>,
|
||||
}
|
||||
|
||||
impl Homeserver {
|
||||
pub async fn start() -> Result<Self> {
|
||||
let app = crate::routes::create_app();
|
||||
|
||||
let mut tasks = JoinSet::new();
|
||||
|
||||
let app = app.clone();
|
||||
|
||||
let listener = TcpListener::bind(SocketAddr::from((
|
||||
[127, 0, 0, 1],
|
||||
6287, // config.port()
|
||||
)))
|
||||
.await?;
|
||||
|
||||
let bound_addr = listener.local_addr()?;
|
||||
|
||||
// Spawn http server task
|
||||
tasks.spawn(
|
||||
axum::serve(
|
||||
listener,
|
||||
app.into_make_service_with_connect_info::<SocketAddr>(),
|
||||
)
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
.into_future(),
|
||||
);
|
||||
|
||||
info!("HTTP server listening on {bound_addr}");
|
||||
|
||||
Ok(Self { tasks })
|
||||
}
|
||||
|
||||
// === Public Methods ===
|
||||
|
||||
/// Shutdown the server and wait for all tasks to complete.
|
||||
pub async fn shutdown(mut self) -> Result<()> {
|
||||
self.tasks.abort_all();
|
||||
self.run_until_done().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Wait for all tasks to complete.
|
||||
///
|
||||
/// Runs forever unless tasks fail.
|
||||
pub async fn run_until_done(mut self) -> Result<()> {
|
||||
let mut final_res: Result<()> = Ok(());
|
||||
while let Some(res) = self.tasks.join_next().await {
|
||||
match res {
|
||||
Ok(Ok(())) => {}
|
||||
Err(err) if err.is_cancelled() => {}
|
||||
Ok(Err(err)) => {
|
||||
warn!(?err, "task failed");
|
||||
final_res = Err(Error::from(err));
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(?err, "task panicked");
|
||||
final_res = Err(err.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
final_res
|
||||
}
|
||||
}
|
||||
|
||||
async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install Ctrl+C handler");
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let terminate = std::future::pending::<()>();
|
||||
|
||||
fn graceful_shutdown() {
|
||||
info!("Gracefully Shutting down..");
|
||||
}
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => graceful_shutdown(),
|
||||
_ = terminate => graceful_shutdown(),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user