#![deny(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
mod config;
mod context;
mod extensions;
mod layers;
mod methods;
mod store;
mod util;
use std::{path::PathBuf, sync::Arc};
use clap::Parser;
use rand::RngCore;
use tracing::info;
use crate::{
context::Context,
store::{AccountAccessLevel, AccountProvider, UserProvider},
};
#[derive(Parser, Debug)]
#[clap(author, version, about)]
pub struct Args {
#[clap(long, short)]
config: PathBuf,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();
let subscriber = tracing_subscriber::fmt();
#[cfg(debug_assertions)]
let subscriber = subscriber.pretty();
subscriber.init();
let config = toml::from_str(&tokio::fs::read_to_string(&args.config).await?)?;
let context = Arc::new(Context::new(config));
create_root_if_none_exists(&context).await;
axum::Server::bind(&"0.0.0.0:8888".parse().unwrap())
.serve(methods::router(context).into_make_service())
.await?;
Ok(())
}
async fn create_root_if_none_exists(context: &Context) {
if context.store.has_any_users().await.unwrap() {
return;
}
let mut password = [0_u8; 32];
rand::thread_rng().fill_bytes(&mut password);
let password = hex::encode(password);
info!("User root created with password {password}");
let root_user = store::User::new("root".into(), &password);
let root_user_id = root_user.id;
context.store.create_user(root_user).await.unwrap();
let root_account = store::Account::new("root".into(), true, false);
let root_account_id = root_account.id;
context.store.create_account(root_account).await.unwrap();
context
.store
.attach_account_to_user(root_account_id, root_user_id, AccountAccessLevel::Owner)
.await
.unwrap();
}