feat: switched to clap for CLI
This commit is contained in:
parent
7cf0e44b65
commit
3800534a51
7 changed files with 238 additions and 25 deletions
57
src/cli.rs
Normal file
57
src/cli.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct Cli {
|
||||
#[arg(
|
||||
long = "templates",
|
||||
default_value = "./templates",
|
||||
value_name = "TEMPLATES_DIR",
|
||||
env = "TEMPLATES_DIR"
|
||||
)]
|
||||
pub templates_dir: PathBuf,
|
||||
#[arg(
|
||||
long = "static",
|
||||
default_value = "./static",
|
||||
value_name = "STATIC_DIR",
|
||||
env = "STATIC_DIR"
|
||||
)]
|
||||
pub static_dir: PathBuf,
|
||||
#[arg(
|
||||
long = "data",
|
||||
default_value = "./data",
|
||||
value_name = "DATA_DIR",
|
||||
env = "DATA_DIR"
|
||||
)]
|
||||
pub data_dir: PathBuf,
|
||||
|
||||
#[command(subcommand)]
|
||||
pub cmd: Subcommands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum Subcommands {
|
||||
Serve { domain: String, port: u16 },
|
||||
User(UserCmd),
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct UserCmd {
|
||||
#[command(subcommand)]
|
||||
cmd: UserSubCmd,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum UserSubCmd {
|
||||
List,
|
||||
Remove {
|
||||
username: String,
|
||||
},
|
||||
Add {
|
||||
username: String,
|
||||
password: String,
|
||||
#[arg(long, default_value_t = false)]
|
||||
admin: bool,
|
||||
},
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
use argon2::password_hash::rand_core::{OsRng, RngCore};
|
||||
use rand::Rng;
|
||||
use rusqlite::Row;
|
||||
|
||||
|
|
|
|||
59
src/main.rs
59
src/main.rs
|
|
@ -1,8 +1,12 @@
|
|||
mod cli;
|
||||
mod db;
|
||||
mod server;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::{fs, path::Path, sync::Arc};
|
||||
|
||||
use clap::Parser;
|
||||
use cli::UserCmd;
|
||||
use db::DbError;
|
||||
use r2d2_sqlite::SqliteConnectionManager;
|
||||
use tera::Tera;
|
||||
use tower_http::compression::CompressionLayer;
|
||||
|
|
@ -14,6 +18,7 @@ const MIGRATIONS: [&str; 5] = [
|
|||
include_str!("migrations/003_events.sql"),
|
||||
include_str!("migrations/004_auth.sql"),
|
||||
];
|
||||
const DB_FILENAME: &str = "db.sqlite3";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Context {
|
||||
|
|
@ -21,31 +26,47 @@ pub struct Context {
|
|||
tera: Arc<Tera>,
|
||||
}
|
||||
|
||||
fn run_user_cli(data_dir: impl AsRef<Path>, cmd: UserCmd) -> Result<(), DbError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt::init();
|
||||
let args = cli::Cli::parse();
|
||||
|
||||
let manager = SqliteConnectionManager::file("db.sqlite");
|
||||
let pool = r2d2::Pool::new(manager).unwrap();
|
||||
db::run_migrations(&pool, &MIGRATIONS).unwrap();
|
||||
match args.cmd {
|
||||
cli::Subcommands::Serve { domain, port } => {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let template_dir = std::env::var("TEMPLATE_DIR").unwrap_or(String::from("./templates"));
|
||||
let tera = Tera::new(&format!("{template_dir}/**/*")).unwrap();
|
||||
if !fs::exists(&args.data_dir).unwrap() {
|
||||
fs::create_dir_all(&args.data_dir).unwrap();
|
||||
}
|
||||
|
||||
let static_dir = std::env::var("STATIC_DIR").unwrap_or(String::from("./static"));
|
||||
let manager = SqliteConnectionManager::file(args.data_dir.join(DB_FILENAME));
|
||||
let pool = r2d2::Pool::new(manager).unwrap();
|
||||
db::run_migrations(&pool, &MIGRATIONS).unwrap();
|
||||
|
||||
let ctx = Context {
|
||||
pool,
|
||||
tera: Arc::new(tera),
|
||||
};
|
||||
let app = server::app(ctx, &static_dir).layer(CompressionLayer::new().br(true).gzip(true));
|
||||
let tera =
|
||||
Tera::new(&format!("{}/**/*", args.templates_dir.to_string_lossy())).unwrap();
|
||||
|
||||
let address = "0.0.0.0:8000";
|
||||
let ctx = Context {
|
||||
pool,
|
||||
tera: Arc::new(tera),
|
||||
};
|
||||
let app = server::app(ctx, &args.static_dir)
|
||||
.layer(CompressionLayer::new().br(true).gzip(true));
|
||||
|
||||
tracing::info!("Starting server on {address}");
|
||||
let address = format!("{}:{}", domain, port);
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(address).await.unwrap();
|
||||
axum::serve(listener, app.into_make_service())
|
||||
.await
|
||||
.unwrap();
|
||||
tracing::info!("Starting server on {address}");
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(address).await.unwrap();
|
||||
axum::serve(listener, app.into_make_service())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
cli::Subcommands::User(cmd) => {
|
||||
run_user_cli(&args.data_dir, cmd).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ mod error;
|
|||
mod events;
|
||||
mod plants;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use axum::{
|
||||
extract::State,
|
||||
http::{header::VARY, HeaderMap, HeaderValue},
|
||||
|
|
@ -50,7 +52,7 @@ pub fn render_view(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn app(ctx: crate::Context, static_dir: &str) -> axum::Router {
|
||||
pub fn app(ctx: crate::Context, static_dir: impl AsRef<Path>) -> axum::Router {
|
||||
let router = Router::new()
|
||||
.nest("/plants", plants::app())
|
||||
.nest("/comments", comments::app())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue