Add AppState, DB and Snafu

This commit is contained in:
gabatxo1312 2026-01-26 01:05:10 +01:00
parent e8529bdbee
commit a3c0b194e1
11 changed files with 2394 additions and 25 deletions

2274
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -19,4 +19,8 @@ serde = "1.0.228"
# static-serve = "0.4.0"
static-serve = { git = "https://github.com/M4SS-Code/static-serve" }
tokio = { version = "1.49.0", features = ["macros", "rt-multi-thread"] }
sea-orm = { version = "2.0.0-rc", features = [ "runtime-tokio", "debug-print", "sqlx-sqlite"] }
camino = { version = "1.2.2", features = [ "serde1" ] }
toml = { version = "0.9.11", features = ["preserve_order"] }
snafu = "0.8.9"
xdg = "3.0.0"

1
config.toml Normal file
View File

@ -0,0 +1 @@
database_path = "/home/torrpenn/projects/Gabatxo1312/bookforge/db.sqlite"

0
db.sqlite Normal file
View File

View File

@ -1,10 +1,13 @@
use axum::{Router, routing::get};
use static_serve::embed_assets;
mod error;
mod routes;
use crate::state::AppState;
pub fn build_app() -> Router {
mod routes;
pub mod state;
pub fn build_app(state: AppState) -> Router {
println!("{:?}", state);
embed_assets!("assets", compress = true);
Router::new()
@ -14,4 +17,5 @@ pub fn build_app() -> Router {
.route("/books/new", get(routes::book::new))
.route("/users", get(routes::user::index))
.nest("/assets", static_router())
.with_state(state)
}

View File

@ -1,10 +1,35 @@
use bookforge::build_app;
use bookforge::state::error::AppStateError;
use snafu::prelude::*;
#[tokio::main(flavor = "current_thread")]
async fn main() {
let app = build_app();
use bookforge::build_app;
use bookforge::state::AppState;
#[derive(Snafu, Debug)]
enum AppError {
#[snafu(display("Failed to initialize AppState"))]
State {
source: AppStateError,
},
Error,
}
async fn main_inner() -> Result<(), AppError> {
let app = build_app(AppState::new().await.context(StateSnafu)?);
let listener = tokio::net::TcpListener::bind("0.0.0.0:8000").await.unwrap();
let _ = axum::serve(listener, app).await;
Ok(())
}
#[tokio::main(flavor = "current_thread")]
async fn main() {
if let Err(_errors) = main_inner().await {
// for error in errors.iter_chain() {
// println!("{}", error);
// }
std::process::exit(1);
}
}

View File

@ -2,7 +2,7 @@ use askama::Template;
use askama_web::WebTemplate;
use axum::extract::Path;
use crate::error::AppStateError;
use crate::state::error::AppStateError;
#[derive(Template, WebTemplate)]
#[template(path = "index.html")]

View File

@ -1,7 +1,7 @@
use askama::Template;
use askama_web::WebTemplate;
use crate::error::AppStateError;
use crate::state::error::AppStateError;
#[derive(Template, WebTemplate)]
#[template(path = "users/index.html")]

51
src/state/config.rs Normal file
View File

@ -0,0 +1,51 @@
use snafu::prelude::*;
use tokio::fs::read_to_string;
use camino::Utf8PathBuf;
use serde::{Deserialize, Serialize};
use xdg::BaseDirectories;
#[derive(Snafu, Debug)]
pub enum ConfigError {
#[snafu(display("File doesn't exist at path : {path}"))]
FailedReadConfig {
path: Utf8PathBuf,
source: std::io::Error,
},
#[snafu(display("Failed parse config : {path}"))]
FailedParseConfig {
path: Utf8PathBuf,
source: toml::de::Error,
},
}
#[derive(Clone, Deserialize, Serialize, Debug)]
pub struct AppConfig {
#[serde(default = "AppConfig::default_sqlite_path")]
pub database_path: Utf8PathBuf,
}
impl AppConfig {
pub async fn new() -> Result<Self, ConfigError> {
// TODO: Remove this
let path = Utf8PathBuf::from("/home/torrpenn/projects/Gabatxo1312/bookforge/config.toml");
let content = read_to_string(&path).await.context(FailedReadConfigSnafu {
path: path.to_path_buf(),
})?;
toml::from_str(&content).context(FailedParseConfigSnafu {
path: path.to_path_buf(),
})
}
pub fn xdg_base_directories() -> BaseDirectories {
BaseDirectories::with_prefix("bookforge")
}
pub fn default_sqlite_path() -> Utf8PathBuf {
let config_dir = Self::xdg_base_directories().get_config_home().unwrap();
Utf8PathBuf::from_path_buf(config_dir).unwrap()
}
}

View File

@ -1,13 +1,26 @@
use askama::Template;
use askama_web::WebTemplate;
use axum::response::{IntoResponse, Response};
use snafu::prelude::*;
use crate::state::config::ConfigError;
#[derive(Template, WebTemplate)]
#[template(path = "error.html")]
struct ErrorTemplate {}
#[derive(Snafu, Debug)]
#[snafu(visibility(pub))]
pub enum AppStateError {
Error,
#[snafu(display("Sqlite Error"))]
Sqlite {
source: sea_orm::error::DbErr,
},
#[snafu(display("Config Error"))]
ConfigError {
source: ConfigError,
},
}
impl IntoResponse for AppStateError {

27
src/state/mod.rs Normal file
View File

@ -0,0 +1,27 @@
use sea_orm::{Database, DatabaseConnection};
use snafu::prelude::*;
use crate::state::config::AppConfig;
use error::*;
pub mod config;
pub mod error;
#[derive(Clone, Debug)]
pub struct AppState {
pub config: AppConfig,
pub db: DatabaseConnection,
}
impl AppState {
pub async fn new() -> Result<Self, AppStateError> {
let config: AppConfig = AppConfig::new().await.context(ConfigSnafu)?;
let db: DatabaseConnection =
Database::connect(format!("sqlite:{}?mode=rwc", &config.database_path))
.await
.context(SqliteSnafu)?;
Ok(Self { config, db })
}
}