calathea/src/main.rs

89 lines
2.1 KiB
Rust

mod server;
use std::sync::Arc;
use r2d2_sqlite::{rusqlite, SqliteConnectionManager};
use tera::Tera;
pub type DbPool = r2d2::Pool<SqliteConnectionManager>;
const MIGRATIONS: [&str; 2] = [
include_str!("migrations/000_initial.sql"),
include_str!("migrations/001_plants.sql"),
];
#[derive(Clone)]
pub struct Context {
pool: crate::DbPool,
tera: Arc<Tera>,
}
#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
let manager = SqliteConnectionManager::file("db.sqlite");
let pool = r2d2::Pool::new(manager).unwrap();
run_migrations(&pool).unwrap();
let tera = load_templates();
let ctx = Context {
pool,
tera: Arc::new(tera),
};
let app = server::app(ctx);
let address = "0.0.0.0:8000";
tracing::info!("Starting server on {address}");
let listener = tokio::net::TcpListener::bind(address).await.unwrap();
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}
fn run_migrations(pool: &DbPool) -> rusqlite::Result<()> {
let mut conn = pool.get().unwrap();
// If the migration version query fails, we assume it's because the table isn't there yet so we
// try to run the first migration
let mut next_version = conn
.query_row("select max(version) from migration_version", (), |row| {
row.get::<_, usize>(0).map(|n| n + 1)
})
.unwrap_or(0);
while next_version < MIGRATIONS.len() {
let tx = conn.transaction()?;
tx.execute(MIGRATIONS[next_version], ())?;
let cur_time = chrono::Local::now().timestamp();
tx.execute(
"insert into migration_version values ($1, $2)",
(next_version, cur_time),
)?;
tx.commit()?;
tracing::info!("Applied migration {next_version}");
next_version += 1;
}
Ok(())
}
fn load_templates() -> Tera {
let mut tera = Tera::default();
tera.add_raw_templates(vec![
("index.html", include_str!("templates/index.html")),
("plant_li.html", include_str!("templates/plant_li.html")),
])
.unwrap();
tera
}