This commit is contained in:
parent
0f7e7994ff
commit
f5fc85cb00
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1081,6 +1081,7 @@ dependencies = [
|
|||||||
"axum",
|
"axum",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-appender",
|
"tracing-appender",
|
||||||
|
|||||||
@ -12,3 +12,4 @@ tracing-tree = "0.4.1"
|
|||||||
tokio = { version = "1.52.1", features = ["rt-multi-thread", "macros", "signal"] }
|
tokio = { version = "1.52.1", features = ["rt-multi-thread", "macros", "signal"] }
|
||||||
sqlx = { version = "0.8", features = [ "runtime-tokio", "postgres", "time", "uuid" ] }
|
sqlx = { version = "0.8", features = [ "runtime-tokio", "postgres", "time", "uuid" ] }
|
||||||
axum = "0.8.9"
|
axum = "0.8.9"
|
||||||
|
thiserror = "2"
|
||||||
|
|||||||
@ -2,6 +2,8 @@ use std::env;
|
|||||||
|
|
||||||
use dotenvy::dotenv;
|
use dotenvy::dotenv;
|
||||||
|
|
||||||
|
use crate::errors::AppError;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum AppEnv {
|
pub enum AppEnv {
|
||||||
Development,
|
Development,
|
||||||
@ -9,12 +11,15 @@ pub enum AppEnv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AppEnv {
|
impl AppEnv {
|
||||||
pub fn from_env() -> Self {
|
pub fn from_env() -> Result<Self, AppError> {
|
||||||
match std::env::var("APP_ENV").as_deref() {
|
match env::var("APP_ENV").as_deref() {
|
||||||
Ok("prod") => AppEnv::Production,
|
Ok("prod") => Ok(AppEnv::Production),
|
||||||
Ok("dev") => AppEnv::Development,
|
Ok("dev") => Ok(AppEnv::Development),
|
||||||
Ok(other) => panic!("Invalid APP_ENV: {}", other),
|
Ok(other) => Err(AppError::InvalidConfig(format!(
|
||||||
Err(_) => panic!("APP_ENV must be set"),
|
"Invalid APP_ENV: {}",
|
||||||
|
other
|
||||||
|
))),
|
||||||
|
Err(_) => Err(AppError::InvalidConfig("APP_ENV must be set".to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -27,12 +32,12 @@ pub struct Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load() -> Self {
|
pub fn load() -> Result<Self, AppError> {
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
Self {
|
Ok(Self {
|
||||||
db_url: env::var("DB_URL").expect("DB_URL is not configured"),
|
db_url: env::var("DB_URL")?,
|
||||||
socket_address: env::var("SOCKET_ADDRESS").expect("SOCKET_ADDRESS is not configured"),
|
socket_address: env::var("SOCKET_ADDRESS")?,
|
||||||
app_env: AppEnv::from_env(),
|
app_env: AppEnv::from_env()?,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,22 +1,19 @@
|
|||||||
use std::process::exit;
|
use sqlx::{Pool, Postgres, postgres::PgPoolOptions, migrate::MigrateError};
|
||||||
|
|
||||||
use sqlx::{Pool, Postgres, postgres::PgPoolOptions};
|
use crate::errors::AppError;
|
||||||
|
|
||||||
pub async fn init(db_url: &str) -> Pool<Postgres> {
|
pub async fn init(db_url: &str) -> Result<Pool<Postgres>, AppError> {
|
||||||
let db = match PgPoolOptions::new().connect(db_url).await {
|
let db = PgPoolOptions::new()
|
||||||
Ok(p) => p,
|
.connect(db_url)
|
||||||
Err(_) => {
|
.await
|
||||||
tracing::error!("Failed to connect to the database");
|
.map_err(AppError::DbConnect)?;
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match sqlx::migrate!().run(&db).await {
|
|
||||||
Ok(_) => tracing::info!("Migration completed succesfully"),
|
|
||||||
Err(_) => {
|
|
||||||
tracing::error!("Failed to apply migrations");
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
db
|
sqlx::migrate!()
|
||||||
|
.run(&db)
|
||||||
|
.await
|
||||||
|
.map_err(|e: MigrateError| AppError::InvalidConfig(format!("Migration failed: {}", e)))?;
|
||||||
|
|
||||||
|
tracing::info!("Migration completed successfully");
|
||||||
|
|
||||||
|
Ok(db)
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/errors.rs
Normal file
26
src/errors.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum AppError {
|
||||||
|
#[error("Failed to load configuration: {0}")]
|
||||||
|
Config(#[from] std::env::VarError),
|
||||||
|
|
||||||
|
#[error("Invalid configuration value: {0}")]
|
||||||
|
InvalidConfig(String),
|
||||||
|
|
||||||
|
#[error("Failed to connect to database")]
|
||||||
|
DbConnect(#[from] sqlx::Error),
|
||||||
|
|
||||||
|
#[error("Failed to bind to address")]
|
||||||
|
Bind(#[from] std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
#[error("Application error: {0}")]
|
||||||
|
pub struct MainError(pub AppError);
|
||||||
|
|
||||||
|
impl From<AppError> for MainError {
|
||||||
|
fn from(err: AppError) -> Self {
|
||||||
|
Self(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/main.rs
23
src/main.rs
@ -2,27 +2,26 @@ use axum::{Router, routing::get};
|
|||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod database;
|
mod database;
|
||||||
|
mod errors;
|
||||||
mod logging;
|
mod logging;
|
||||||
|
|
||||||
|
use errors::{AppError, MainError};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() -> Result<(), MainError> {
|
||||||
let cfg = config::Config::load();
|
let cfg = config::Config::load()?;
|
||||||
let _logging_guard = logging::LoggerConfig::init(cfg.app_env);
|
let _logging_guard = logging::LoggerConfig::init(cfg.app_env);
|
||||||
let _db = database::init(&cfg.db_url).await;
|
let _db = database::init(&cfg.db_url).await?;
|
||||||
let app = Router::new().route(
|
let app = Router::new().route("/", get(|| async { "ciao" }));
|
||||||
"/",
|
|
||||||
get(|| async {
|
|
||||||
tracing::info!("ciao");
|
|
||||||
return "ciao";
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
let listener = tokio::net::TcpListener::bind(&cfg.socket_address)
|
let listener = tokio::net::TcpListener::bind(&cfg.socket_address)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.map_err(AppError::Bind)?;
|
||||||
|
|
||||||
tracing::info!("Server started on {}", cfg.socket_address);
|
tracing::info!("Server started on {}", cfg.socket_address);
|
||||||
axum::serve(listener, app)
|
axum::serve(listener, app)
|
||||||
.with_graceful_shutdown(logging::shutdown_signal())
|
.with_graceful_shutdown(logging::shutdown_signal())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.map_err(AppError::Bind)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user