pique/src/server.rs

97 lines
3.5 KiB
Rust

use std::str::FromStr;
use anyhow::Result;
use axum::routing::{get, post};
use axum::Router;
use axum_login::AuthManagerLayerBuilder;
use clap::Parser;
use diesel_migrations::{embed_migrations, EmbeddedMigrations};
use tower_http::services::ServeDir;
use tower_http::trace::{DefaultOnRequest, DefaultOnResponse, TraceLayer};
use tower_sessions::SessionManagerLayer;
use tower_sessions_sqlx_store::sqlx::SqlitePool;
use tower_sessions_sqlx_store::SqliteStore;
use tracing::Level;
use crate::config::CommandLineOptions;
use crate::db;
use crate::handler::documents::{
create_document_page, create_document_submit, documents_page, edit_document_page,
edit_document_submit, view_document_page,
};
use crate::handler::home::home_page;
use crate::handler::login::logout;
use crate::handler::projects::{create_project_page, create_project_submit, projects_page};
use crate::handler::{login_page, login_submit};
use crate::logging::setup_logging;
use crate::provider::Provider;
use crate::templates::make_template_loader;
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./migrations/");
pub async fn run() -> Result<()> {
dotenvy::dotenv()?;
setup_logging();
let opts = CommandLineOptions::parse();
let template_loader = make_template_loader(opts.reload_templates);
let db_url = dotenvy::var("DATABASE_URL")?;
let mut db_conn = db::establish_connection(&db_url);
db::migrate(&mut db_conn);
let db_pool = db::build_connection_pool(&db_url);
let session_layer = create_session_manager_layer().await?;
let provider = Provider::new(db_pool, template_loader);
let auth_backend = provider.clone();
let auth_layer = AuthManagerLayerBuilder::new(auth_backend, session_layer.clone()).build();
let trace_layer = TraceLayer::new_for_http()
.on_request(DefaultOnRequest::new().level(Level::INFO))
.on_response(DefaultOnResponse::new().level(Level::INFO));
let app = Router::new()
.nest_service("/static", ServeDir::new("static"))
.route("/", get(home_page))
.route("/login", get(login_page))
.route("/login", post(login_submit))
.route("/logout", get(logout))
.route("/projects", get(projects_page))
.route("/projects/new", get(create_project_page))
.route("/projects/new", post(create_project_submit))
.route("/documents", get(documents_page))
.route("/documents/new", get(create_document_page))
.route("/documents/new", post(create_document_submit))
.route("/documents/view/:id", get(view_document_page))
.route("/documents/edit/:id", get(edit_document_page))
.route("/documents/edit/:id", post(edit_document_submit))
.layer(trace_layer)
.layer(session_layer)
.layer(auth_layer)
.with_state(provider);
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
axum::serve(listener, app).await.unwrap();
Ok(())
}
pub async fn create_session_manager_layer() -> Result<SessionManagerLayer<SqliteStore>> {
let session_db_url =
dotenvy::var("SESSION_DB_URL").unwrap_or("sqlite:./sessions.db?mode=rwc".to_owned());
let pool = SqlitePool::connect(&session_db_url).await?;
let session_store = SqliteStore::new(pool);
session_store.migrate().await?;
let use_secure_sessions: bool =
FromStr::from_str(&dotenvy::var("SECURE_SESSIONS").unwrap_or("true".to_owned()))?;
let session_layer = SessionManagerLayer::new(session_store).with_secure(use_secure_sessions);
Ok(session_layer)
}