add basic migrations
This commit is contained in:
parent
00eca2801f
commit
97d089c284
10 changed files with 251 additions and 29 deletions
|
@ -19,3 +19,7 @@ eyre = "0.6.11"
|
|||
color-eyre = "0.6.2"
|
||||
rsa = { version = "0.9.6", features = ["serde"] }
|
||||
rand = "0.8.5"
|
||||
toml = "0.8.8"
|
||||
tokio = { version = "1.35.1", features = ["macros", "rt-multi-thread"] }
|
||||
tracing-subscriber = "0.3.18"
|
||||
tracing = "0.1.40"
|
||||
|
|
54
identity/src/config.rs
Normal file
54
identity/src/config.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use eyre::Result;
|
||||
use serde::Deserialize;
|
||||
use std::path::Path;
|
||||
use std::{env, fs};
|
||||
use tracing::Level;
|
||||
|
||||
pub const CONFIG_FILE: &str = "config.identity.toml";
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Config {
|
||||
pub database_url: String,
|
||||
pub port: u16,
|
||||
pub auto_migrate: Option<bool>,
|
||||
pub log_level: Option<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn load() -> Result<Self> {
|
||||
let cwd = env::current_dir()?;
|
||||
let config_file = Path::join(cwd.as_path(), Path::new(CONFIG_FILE));
|
||||
println!("config file: {}", config_file.display());
|
||||
|
||||
let s = fs::read_to_string(config_file)?;
|
||||
let config = toml::from_str(s.as_str())?;
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn tracing_level(&self) -> Option<Level> {
|
||||
match self
|
||||
.log_level
|
||||
.as_deref()
|
||||
.unwrap_or("INFO")
|
||||
{
|
||||
"TRACE" => Some(Level::TRACE),
|
||||
"DEBUG" => Some(Level::DEBUG),
|
||||
"INFO" => Some(Level::INFO),
|
||||
"WARN" => Some(Level::WARN),
|
||||
"ERROR" => Some(Level::ERROR),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Config {
|
||||
database_url: env::var("DATABASE_URL").unwrap_or("".into()),
|
||||
port: 3000,
|
||||
auto_migrate: None,
|
||||
log_level: None,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +1,30 @@
|
|||
use std::time::Duration;
|
||||
use eyre::{OptionExt, Result};
|
||||
use rsa::{RsaPrivateKey, RsaPublicKey};
|
||||
use rsa::pkcs1::LineEnding;
|
||||
use rsa::pkcs8::{EncodePrivateKey, EncodePublicKey};
|
||||
use sqlx::{Pool, Postgres};
|
||||
use rsa::{RsaPrivateKey, RsaPublicKey};
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
use sqlx::{Pool, Postgres};
|
||||
use std::time::Duration;
|
||||
|
||||
pub async fn init_db(dsn: &str) -> Result<Pool<Postgres>> {
|
||||
pub async fn init(dsn: &str) -> Result<Pool<Postgres>> {
|
||||
let pool = PgPoolOptions::new()
|
||||
.acquire_timeout(Duration::from_secs(2)) // Fail fast and don't hang
|
||||
.max_connections(100)
|
||||
.connect(dsn)
|
||||
.await?;
|
||||
|
||||
init_instance(&pool)?;
|
||||
|
||||
Ok(pool)
|
||||
}
|
||||
|
||||
const PRIVATE_KEY_BITS: usize = 2048;
|
||||
|
||||
async fn init_instance(pool: &Pool<Postgres>) -> Result<()> {
|
||||
pub async fn init_instance(pool: &Pool<Postgres>) -> Result<()> {
|
||||
let mut tx = pool.begin().await?;
|
||||
|
||||
// Check if we already have an instance configuration
|
||||
let row = sqlx::query!("select exists(select * from instance)").fetch_one(&mut *tx).await?;
|
||||
let row = sqlx::query!("select exists(select * from instance)")
|
||||
.fetch_one(&mut *tx)
|
||||
.await?;
|
||||
if row.exists.ok_or_eyre("exists was null")? {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -34,13 +34,18 @@ async fn init_instance(pool: &Pool<Postgres>) -> Result<()> {
|
|||
let priv_key = RsaPrivateKey::new(&mut rng, PRIVATE_KEY_BITS)?;
|
||||
let pub_key = RsaPublicKey::from(&priv_key);
|
||||
|
||||
let priv_key_string = priv_key.to_pkcs8_pem(LineEnding::default())?;
|
||||
let pub_key_string = pub_key.to_public_key_pem(LineEnding::default())?;
|
||||
let priv_key_string = priv_key.to_pkcs8_pem(LineEnding::LF)?;
|
||||
let pub_key_string = pub_key.to_public_key_pem(LineEnding::LF)?;
|
||||
|
||||
sqlx::query!("insert into instance (public_key, private_key) values ($1, $2)",
|
||||
priv_key_string.to_string(), pub_key_string).execute(&mut *tx).await?;
|
||||
sqlx::query!(
|
||||
"insert into instance (public_key, private_key) values ($1, $2)",
|
||||
priv_key_string.to_string(),
|
||||
pub_key_string
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
mod model;
|
||||
mod config;
|
||||
mod db;
|
||||
mod model;
|
||||
|
||||
use color_eyre::eyre::Result;
|
||||
use crate::config::Config;
|
||||
use clap::{Parser, Subcommand};
|
||||
use ulid::Ulid;
|
||||
use color_eyre::eyre::Result;
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Command,
|
||||
command: Option<Command>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
|
@ -17,18 +19,45 @@ enum Command {
|
|||
Migrate,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
|
||||
let config = Config::load()?;
|
||||
let args = Cli::parse();
|
||||
println!("{args:#?}");
|
||||
|
||||
println!("{}", match args.command {
|
||||
Command::Serve => "serving!",
|
||||
Command::Migrate => "migrating!"
|
||||
});
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(config.tracing_level().unwrap_or(tracing::Level::INFO))
|
||||
.init();
|
||||
|
||||
println!("{}", Ulid::new());
|
||||
match args.command.unwrap_or(Command::Serve) {
|
||||
Command::Serve => main_web(config).await,
|
||||
Command::Migrate => main_migrate(config).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn main_migrate(config: Config) -> Result<()> {
|
||||
info!("Connecting to database");
|
||||
let pool = db::init(&config.database_url).await?;
|
||||
info!("Migrating database");
|
||||
sqlx::migrate!().run(&pool).await?;
|
||||
info!("Migrated database");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn main_web(config: Config) -> Result<()> {
|
||||
info!("Connecting to database");
|
||||
let pool = db::init(&config.database_url).await?;
|
||||
|
||||
if config.auto_migrate.unwrap_or(false) {
|
||||
info!("Auto-migrate is enabled, migrating database");
|
||||
sqlx::migrate!().run(&pool).await?;
|
||||
info!("Migrated database");
|
||||
}
|
||||
|
||||
info!("Initializing instance data");
|
||||
db::init_instance(&pool).await?;
|
||||
info!("Initialized instance data!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -15,4 +15,4 @@ pub struct Account {
|
|||
pub enum Role {
|
||||
User,
|
||||
Admin,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,4 +13,4 @@ pub struct ChatInstance {
|
|||
pub enum InstanceStatus {
|
||||
Active,
|
||||
Suspended,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue