nomilo/src/cli/server.rs

129 lines
3.8 KiB
Rust

use std::net::IpAddr;
use std::process::exit;
use clap::{Parser, Subcommand};
use rocket::{Rocket, Build};
use rocket::fairing::AdHoc;
use rocket::fs::FileServer;
use figment::Figment;
use crate::config::Config;
use crate::routes::api;
use crate::routes::ui;
use crate::{DbConn, get_db_conn};
use crate::cli::NomiloCommand;
use crate::template::TemplateState;
#[derive(Subcommand)]
pub enum ServerCommand {
/// Run web server
Run(RunServerCommand),
/// Run database migrations and exit
Migrate(MigrateCommand),
}
#[derive(Parser)]
pub struct RunServerCommand {
#[clap(long = "--address", short = 'a')]
/// Address to serve application on, override both configuration and environment values
address: Option<IpAddr>,
#[clap(long = "--port", short = 'p')]
/// Port to serve application on, override both configuration and environment values
port: Option<u16>,
}
#[derive(Parser)]
pub struct MigrateCommand;
impl NomiloCommand for ServerCommand {
fn run(self, figment: Figment, app_config: Config) {
match self {
ServerCommand::Run(sub) => sub.run(figment, app_config),
ServerCommand::Migrate(sub) => sub.run(figment, app_config),
};
}
}
fn run_migrations(conn: &diesel::SqliteConnection) -> Result<(), diesel_migrations::RunMigrationsError> {
embed_migrations!("migrations");
embedded_migrations::run(conn)
}
async fn run_migrations_fairing(rocket: Rocket<Build>) -> Rocket<Build> {
embed_migrations!("migrations");
let conn = match DbConn::get_one(&rocket).await {
Some(c) => c,
None => {
error!("Could not get a database connection");
exit(1);
}
};
if let Err(e) = conn.run(|c| run_migrations(&c)).await {
error!("Error running migrations: {}", e);
exit(1);
}
rocket
}
impl NomiloCommand for RunServerCommand {
fn run(self, mut figment: Figment, app_config: Config) {
rocket::async_main(async move {
if let Some(address) = self.address {
figment = figment.merge(("address", address));
}
if let Some(port) = self.port {
figment = figment.merge(("port", port));
}
let template_state = TemplateState::new(&app_config.web_app.templates_directory);
let static_files = FileServer::from(&app_config.web_app.static_files);
let _res = rocket::custom(figment)
.manage(app_config)
.manage(template_state)
.attach(DbConn::fairing())
.attach(AdHoc::on_ignite("Database migration", run_migrations_fairing))
.mount("/api/v1", routes![
api::get_zone_records,
api::create_zone_records,
api::update_zone_records,
api::delete_zone_records,
api::get_zones,
api::create_zone,
api::add_member_to_zone,
api::create_auth_token,
api::create_user,
])
.mount("/", routes![
ui::get_login_page,
ui::post_login_page,
ui::get_zones_page,
ui::get_zone_records_page,
ui::get_create_zone_page,
ui::post_create_zone_page,
])
.mount("/", static_files)
.launch().await;
});
}
}
impl NomiloCommand for MigrateCommand {
fn run(self, figment: Figment, _app_config: Config) {
let conn = get_db_conn(&figment);
match run_migrations(&conn) {
Ok(_) => println!("Migrations ran successfully"),
Err(e) => {
error!("Error running migrations: {}", e);
exit(1);
}
}
}
}