feat: add scafolding

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2025-03-27 11:07:54 +00:00
parent 0e141eebae
commit 4f0f8ddbe1
15 changed files with 4648 additions and 100 deletions

66
src/config.rs Normal file
View File

@@ -0,0 +1,66 @@
use serde::Deserialize;
use std::{
fs,
net::{IpAddr, Ipv4Addr},
path::PathBuf,
};
#[derive(Deserialize)]
pub struct ServerConfig {
#[serde(default = "default_address")]
pub address: std::net::IpAddr,
#[serde(default = "default_port")]
pub port: u16,
#[serde(default)]
pub subpath: String,
}
const fn default_address() -> IpAddr {
IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))
}
const fn default_port() -> u16 {
51821
}
impl Default for ServerConfig {
fn default() -> Self {
Self {
address: default_address(),
port: default_port(),
subpath: String::default(),
}
}
}
#[derive(Deserialize)]
pub struct DatabaseConfig {
pub user: String,
pub password: String,
pub host: String,
pub port: u16,
pub database: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct OidcConfig {
pub issuer_url: String,
pub client_id: String,
pub client_secret: String,
}
#[derive(Deserialize)]
pub struct Config {
#[serde(default)]
pub server: ServerConfig,
pub database: DatabaseConfig,
pub oidc: OidcConfig,
}
impl Config {
pub fn from_yaml(path: &PathBuf) -> Result<Self, Box<dyn std::error::Error>> {
let contents = fs::read_to_string(path)?;
let config = serde_yaml::from_str(&contents)?;
Ok(config)
}
}

57
src/main.rs Normal file
View File

@@ -0,0 +1,57 @@
#![warn(clippy::all, clippy::pedantic, clippy::nursery)]
#![allow(clippy::missing_docs_in_private_items)]
mod config;
mod routes;
use axum::{Extension, serve};
use clap::Parser;
use log::info;
use log4rs::config::Deserializers;
use sqlx::postgres::PgPoolOptions;
use std::{net::SocketAddr, path::PathBuf};
use tokio::net::TcpListener;
use config::Config;
#[derive(Parser, Debug)]
#[command(version, about, long_about = None, author)]
struct Args {
/// Path to the YAML config file
#[arg(short, long, value_name = "FILE", default_value = "config.yaml")]
config: PathBuf,
/// Path to the log4rs config file
#[arg(short, long, value_name = "FILE", default_value = "log4rs.yaml")]
log_config: PathBuf,
}
#[tokio::main]
async fn main() {
let args = Args::parse();
log4rs::init_file(args.log_config, Deserializers::default()).unwrap();
let config = Config::from_yaml(&args.config).unwrap();
let pgpool = PgPoolOptions::new()
.max_connections(5)
.connect(&format!(
"postgres://{}:{}@{}:{}/{}",
config.database.user,
config.database.password,
config.database.host,
config.database.port,
config.database.database
))
.await
.unwrap();
let routes = routes::routes();
let app = axum::Router::new()
.nest(&format!("{}/api", config.server.subpath), routes)
.layer(Extension(pgpool));
let addr = SocketAddr::from((config.server.address, config.server.port));
let listener = TcpListener::bind(addr).await.unwrap();
info!("Listening on {addr}.");
serve(listener, app).await.unwrap();
}

9
src/routes/health.rs Normal file
View File

@@ -0,0 +1,9 @@
use axum::{Router, http::StatusCode, routing};
pub async fn get() -> Result<StatusCode, StatusCode> {
Ok(StatusCode::OK)
}
pub fn routes() -> Router {
Router::new().route("/", routing::get(get))
}

9
src/routes/mod.rs Normal file
View File

@@ -0,0 +1,9 @@
mod health;
use axum::Router;
pub fn routes() -> Router {
let health = health::routes();
Router::new().merge(health)
}