database connectivity

This commit is contained in:
core 2023-02-02 21:39:41 -05:00
parent 83982551ca
commit 757d324db6
Signed by: core
GPG Key ID: FDBF740DADDCEECF
6 changed files with 829 additions and 8 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
target

737
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,4 +8,9 @@ edition = "2021"
[dependencies] [dependencies]
rocket = { version = "0.5.0-rc.2", features = ["json"] } rocket = { version = "0.5.0-rc.2", features = ["json"] }
base64 = "0.21.0" base64 = "0.21.0"
log = "0.4.17" log = "0.4.17"
sqlx = { version = "0.6", features = [ "runtime-tokio-native-tls" , "postgres" ] }
tokio = { version = "1", features = ["full"] }
toml = "0.7.1"
serde = "1.0.152"
dotenvy = "0.15.6"

2
trifid-api/config.toml Normal file
View File

@ -0,0 +1,2 @@
listen_port = 8000
db_url = "postgres://postgres@localhost/trifidapi"

7
trifid-api/src/config.rs Normal file
View File

@ -0,0 +1,7 @@
use serde::Deserialize;
#[derive(Deserialize)]
pub struct TFConfig {
pub listen_port: u16,
pub db_url: String
}

View File

@ -1,12 +1,23 @@
use rocket::{routes, post}; use std::error::Error;
use std::fs;
use std::path::Path;
use dotenvy::dotenv;
use log::{error, info};
use rocket::{routes, post, State, Rocket, Ignite};
use rocket::{serde::Serialize}; use rocket::{serde::Serialize};
use rocket::http::{ContentType, Status}; use rocket::http::{ContentType, Status};
use rocket::serde::Deserialize; use rocket::serde::Deserialize;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use sqlx::migrate::Migrator;
use sqlx::PgPool;
use sqlx::postgres::PgPoolOptions;
use crate::config::TFConfig;
use crate::format::{validate_dh_pubkey_base64, validate_ed_pubkey_base64}; use crate::format::{validate_dh_pubkey_base64, validate_ed_pubkey_base64};
pub mod format; pub mod format;
pub mod util; pub mod util;
pub mod db;
pub mod config;
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
@ -63,7 +74,7 @@ pub const ERR_MSG_MALFORMED_REQUEST: &str = "unable to parse the request body -
pub const ERR_MSG_MALFORMED_REQUEST_CODE: &str = "ERR_MALFORMED_REQUEST"; pub const ERR_MSG_MALFORMED_REQUEST_CODE: &str = "ERR_MALFORMED_REQUEST";
#[post("/v2/enroll", data = "<request>")] #[post("/v2/enroll", data = "<request>")]
fn enroll_endpoint(request: String) -> Result<(ContentType, Json<EnrollResponse>), (Status, Json<APIError>)> { fn enroll_endpoint(request: String, pool: &State<PgPool>) -> Result<(ContentType, Json<EnrollResponse>), (Status, Json<APIError>)> {
let request: EnrollRequest = match rocket::serde::json::from_str(request.as_str()) { let request: EnrollRequest = match rocket::serde::json::from_str(request.as_str()) {
Ok(r) => r, Ok(r) => r,
Err(e) => { Err(e) => {
@ -94,8 +105,72 @@ fn dnclient_endpoint() -> &'static str {
"DNClient functionality is not yet implemented" "DNClient functionality is not yet implemented"
} }
static MIGRATOR: Migrator = sqlx::migrate!();
#[rocket::main] #[rocket::main]
async fn main() { async fn main() -> Result<(), Box<dyn Error>> {
let _ = rocket::build().mount("/", routes![enroll_endpoint, dnclient_endpoint]).launch().await; let _ = rocket::build();
info!("[tfapi] loading config");
let _ = dotenv();
if std::env::var("CONFIG_FILE").is_err() && !Path::new("config.toml").exists() {
error!("[tfapi] fatal: the environment variable CONFIG_FILE is not set");
error!("[tfapi] help: try creating a .env file that sets it");
error!("[tfapi] help: or, create a file config.toml with your config, as it is loaded automatically");
std::process::exit(1);
}
let config_file;
if Path::new("config.toml").exists() {
config_file = "config.toml".to_string();
} else {
config_file = std::env::var("CONFIG_FILE").unwrap();
}
let config_data = match fs::read_to_string(&config_file) {
Ok(d) => d,
Err(e) => {
error!("[tfapi] fatal: unable to read config from {}", config_file);
error!("[tfapi] fatal: {}", e);
std::process::exit(1);
}
};
let config: TFConfig = match toml::from_str(&config_data) {
Ok(c) => c,
Err(e) => {
error!("[tfapi] fatal: unable to parse config from {}", config_file);
error!("[tfapi] fatal: {}", e);
std::process::exit(1);
}
};
info!("[tfapi] connecting to database pool");
let pool = match PgPoolOptions::new().max_connections(5).connect(&config.db_url).await {
Ok(p) => p,
Err(e) => {
error!("[tfapi] fatal: unable to connect to database pool");
error!("[tfapi] fatal: {}", e);
std::process::exit(1);
}
};
info!("[tfapi] running database migrations");
MIGRATOR.run(&pool).await?;
info!("[tfapi] building rocket config");
let figment = rocket::Config::figment().merge(("port", config.listen_port));
let _ = rocket::custom(figment)
.mount("/", routes![enroll_endpoint, dnclient_endpoint])
.manage(pool)
.manage(config)
.launch().await?;
Ok(())
} }