axum_kit/
bootstrap.rs

1#[cfg(feature = "postgres")]
2use crate::postgres;
3
4#[cfg(feature = "redis")]
5use crate::redis;
6
7use crate::{
8    config::{load_config, Config},
9    general, logger,
10};
11use anyhow::{Context, Result};
12use axum::Router;
13use tracing_appender::non_blocking::WorkerGuard;
14
15type TaskHandle = tokio::task::JoinHandle<Result<()>>;
16
17pub struct Application {
18    config: Config,
19    router_fn: Option<Box<dyn FnOnce() -> Router + Send + Sync>>,
20    pre_run_fn: Option<Box<dyn FnOnce() -> TaskHandle + Send + Sync>>,
21}
22
23impl Application {
24    pub fn default(config_path: &str) -> Result<Self> {
25        let config = load_config(config_path).with_context(|| "configuration parsing failed")?;
26        Ok(Self::new(config))
27    }
28
29    pub fn new(config: Config) -> Self {
30        Self {
31            config,
32            router_fn: None,
33            pre_run_fn: None,
34        }
35    }
36
37    pub fn with_router<F>(mut self, callback: F) -> Self
38    where
39        F: FnOnce() -> Router + Send + Sync + 'static,
40    {
41        self.router_fn = Some(Box::new(callback));
42        self
43    }
44
45    pub fn before_run<F>(mut self, callback: F) -> Self
46    where
47        F: FnOnce() -> TaskHandle + Send + Sync + 'static,
48    {
49        self.pre_run_fn = Some(Box::new(callback));
50        self
51    }
52
53    pub async fn run(self) -> Result<WorkerGuard> {
54        #[cfg(feature = "postgres")]
55        postgres::init(&self.config.postgres)
56            .await
57            .with_context(|| "postgres initialization failed")?;
58
59        #[cfg(feature = "redis")]
60        redis::init(&self.config.redis)
61            .await
62            .with_context(|| "redis initialization failed")?;
63
64        if let Some(callback) = self.pre_run_fn {
65            let _ = callback().await?;
66        }
67        let worker_guard =
68            logger::init(&self.config.logger).with_context(|| "logger initialization failed")?;
69        let router = self
70            .router_fn
71            .map(|callback| callback())
72            .unwrap_or_else(|| {
73                Router::new().route("/", axum::routing::get(|| async { "Hello, Axum-kit!" }))
74            });
75        general::serve(&self.config.general, router)
76            .await
77            .with_context(|| "service startup failed")?;
78
79        Ok(worker_guard)
80    }
81}