Compare commits

...

5 commits

10 changed files with 85 additions and 33 deletions

View file

@ -11,6 +11,7 @@
<sourceFolder url="file://$MODULE_DIR$/acrate_rd/tests" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/acrate_rd/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/acrate_mime/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/acrate_mime/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/acrate_rdserver/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/acrate_rdserver/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/acrate_database/tests" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" /> <excludeFolder url="file://$MODULE_DIR$/target" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />

View file

@ -21,7 +21,9 @@ pretty_env_logger = { version = "0.5.0", optional = true }
uuid = "1.11.0" uuid = "1.11.0"
[features] [features]
bin = ["diesel_migrations", "micronfig", "pretty_env_logger"] default = ["connect"]
bin = ["diesel_migrations", "pretty_env_logger", "connect"]
connect = ["micronfig"]
[lib] [lib]
name = "acrate_database" name = "acrate_database"

View file

@ -13,38 +13,25 @@
//! //!
use std::process::exit; use std::process::exit;
use diesel::{Connection, PgConnection}; use diesel::PgConnection;
use diesel_migrations::{EmbeddedMigrations, MigrationHarness}; use diesel_migrations::{EmbeddedMigrations, MigrationHarness};
use acrate_database::connect::managed_connect_sync;
mod config {
micronfig::config! {
ACRATE_DATABASE_DATABASE_URL: String,
}
}
pub const MIGRATIONS: EmbeddedMigrations = diesel_migrations::embed_migrations!(); pub const MIGRATIONS: EmbeddedMigrations = diesel_migrations::embed_migrations!();
fn main() { fn managed_run_migrations(mut db: PgConnection) {
pretty_env_logger::init();
log::info!("Logging initialized successfully!");
log::trace!("Determining database URL...");
let db = config::ACRATE_DATABASE_DATABASE_URL();
log::debug!("Connecting to: {db:?}");
let mut db = match PgConnection::establish(db) {
Err(e) => {
log::error!("Failed to connect to the PostgreSQL database: {e:#?}");
exit(1);
}
Ok(db) => db,
};
log::debug!("Running migrations..."); log::debug!("Running migrations...");
if let Err(e) = db.run_pending_migrations(MIGRATIONS) { if let Err(e) = db.run_pending_migrations(MIGRATIONS) {
log::error!("Failed to perform migration: {e:#?}"); log::error!("Failed to perform migration: {e:#?}");
exit(2); exit(2);
}; };
log::info!("Migrations applied successfully!") log::info!("Migrations applied successfully!")
} }
fn main() {
pretty_env_logger::init();
log::info!("Logging initialized successfully!");
let db = managed_connect_sync();
managed_run_migrations(db);
}

View file

@ -0,0 +1,5 @@
//! Configuration relative to the database that applies to all crates making use of it.
micronfig::config! {
ACRATE_DATABASE_URL: String,
}

View file

@ -0,0 +1,51 @@
use diesel::{Connection, ConnectionResult, PgConnection};
use diesel_async::{AsyncConnection, AsyncPgConnection};
use crate::config;
/// Create a [`PgConnection`] to the configured database.
pub fn connect_sync() -> ConnectionResult<PgConnection> {
log::trace!("Determining the database URL for a sync connection...");
let database_url = config::ACRATE_DATABASE_URL();
log::trace!("Establishing a sync connection to the database at: {database_url:?}");
PgConnection::establish(database_url)
}
/// Create an [`AsyncPgConnection`] to the configured database.
pub async fn connect_async() -> ConnectionResult<AsyncPgConnection> {
log::trace!("Determining the database URL for an async connection...");
let database_url = config::ACRATE_DATABASE_URL();
log::trace!("Establishing an async connection to the database at: {database_url:?}");
AsyncPgConnection::establish(database_url).await
}
/// Run [`connect_sync`], then handle errors by logging the error and exiting the process with `1`.
pub fn managed_connect_sync() -> PgConnection {
log::trace!("Attempting a managed sync connection to the database...");
match connect_sync() {
Err(e) => {
log::error!("Failed to connect to the database: {e:#?}");
std::process::exit(1);
},
Ok(conn) => {
conn
},
}
}
/// Run [`connect_async`], then handle errors by logging the error and exiting the process with `1`.
pub async fn managed_connect_async() -> AsyncPgConnection {
log::trace!("Attempting a managed async connection to the database...");
match connect_async().await {
Err(e) => {
log::error!("Failed to connect to the database: {e:#?}");
std::process::exit(1);
},
Ok(conn) => {
conn
},
}
}

View file

@ -6,7 +6,15 @@
mod schema; mod schema;
pub mod meta; pub mod meta;
mod macros; mod macros;
#[cfg(feature = "connect")]
mod config;
#[cfg(feature = "connect")]
pub mod connect;
pub use diesel; pub use diesel;
pub use diesel_async; pub use diesel_async;

View file

@ -28,7 +28,6 @@
use diesel::deserialize::FromSql; use diesel::deserialize::FromSql;
use diesel::{AsExpression, Associations, FromSqlRow, Identifiable, Insertable, IntoSql, PgTextExpressionMethods, QueryResult, Queryable, QueryableByName, Selectable, SelectableHelper, ExpressionMethods, BelongingToDsl}; use diesel::{AsExpression, Associations, FromSqlRow, Identifiable, Insertable, IntoSql, PgTextExpressionMethods, QueryResult, Queryable, QueryableByName, Selectable, SelectableHelper, ExpressionMethods, BelongingToDsl};
use diesel::dsl::insert_into;
use diesel::pg::{Pg, PgConnection}; use diesel::pg::{Pg, PgConnection};
use diesel::serialize::{Output, ToSql}; use diesel::serialize::{Output, ToSql};
use diesel_async::AsyncPgConnection; use diesel_async::AsyncPgConnection;

View file

@ -10,7 +10,7 @@ keywords = ["jrd", "xrd", "hostmeta", "webfinger", "resource-descriptor"]
categories = ["web-programming"] categories = ["web-programming"]
[dependencies] [dependencies]
acrate_database = { path = "../acrate_database" } acrate_database = { path = "../acrate_database", features = ["connect"] }
acrate_rd = { path = "../acrate_rd" } acrate_rd = { path = "../acrate_rd" }
anyhow = "1.0.93" anyhow = "1.0.93"
axum = { version = "0.7.7", features = ["macros"] } axum = { version = "0.7.7", features = ["macros"] }
@ -27,3 +27,4 @@ mediatype = { version = "0.19.18", features = ["serde"] }
[lints.clippy] [lints.clippy]
tabs-in-doc-comments = "allow" tabs-in-doc-comments = "allow"
type-complexity = "allow"

View file

@ -1,4 +1,3 @@
micronfig::config!( micronfig::config!(
ACRATE_WEBFINGER_DATABASE_URL: String,
ACRATE_WEBFINGER_BIND_ADDRESS: String, ACRATE_WEBFINGER_BIND_ADDRESS: String,
); );

View file

@ -6,18 +6,17 @@ use axum::http::{HeaderMap, Response, StatusCode};
use axum_extra::extract::Query; use axum_extra::extract::Query;
use mediatype::{MediaTypeBuf, MediaTypeList}; use mediatype::{MediaTypeBuf, MediaTypeList};
use serde::Deserialize; use serde::Deserialize;
use acrate_database::connect::connect_async;
use acrate_database::diesel::GroupedBy; use acrate_database::diesel::GroupedBy;
use acrate_database::diesel_async::{AsyncConnection, AsyncPgConnection};
use acrate_database::meta::{MetaAlias, MetaLink, MetaLinkProperty, MetaLinkTitle, MetaProperty, MetaSubject}; use acrate_database::meta::{MetaAlias, MetaLink, MetaLinkProperty, MetaLinkTitle, MetaProperty, MetaSubject};
use acrate_rd::jrd::ResourceDescriptorLinkJRD; use acrate_rd::jrd::ResourceDescriptorLinkJRD;
use acrate_rd::xrd::{ResourceDescriptorLinkXRD, ResourceDescriptorPropertyXRD, ResourceDescriptorTitleXRD}; use acrate_rd::xrd::{ResourceDescriptorLinkXRD, ResourceDescriptorPropertyXRD, ResourceDescriptorTitleXRD};
use crate::config;
pub async fn healthcheck_handler() -> Result<StatusCode, StatusCode> { pub async fn healthcheck_handler() -> Result<StatusCode, StatusCode> {
log::debug!("Handling an healthcheck request!"); log::debug!("Handling an healthcheck request!");
log::trace!("Making sure the database is up..."); log::trace!("Making sure the database is up...");
let _conn = AsyncPgConnection::establish(config::ACRATE_WEBFINGER_DATABASE_URL()) let _conn = connect_async()
.await .await
.map_err(|_| StatusCode::BAD_GATEWAY)?; .map_err(|_| StatusCode::BAD_GATEWAY)?;
@ -54,12 +53,12 @@ pub async fn webfinger_handler(
let accept = accept let accept = accept
.map(|h| h.to_str()) .map(|h| h.to_str())
.unwrap_or(Ok("*/*")) .unwrap_or(Ok("*/*"))
.map(|h| MediaTypeList::new(h)) .map(MediaTypeList::new)
.map_err(|_| StatusCode::BAD_REQUEST)?; .map_err(|_| StatusCode::BAD_REQUEST)?;
let mut response = Response::new("".to_string()); let mut response = Response::new("".to_string());
let mut conn = AsyncPgConnection::establish(config::ACRATE_WEBFINGER_DATABASE_URL()) let mut conn = connect_async()
.await .await
.map_err(|_| StatusCode::BAD_GATEWAY)?; .map_err(|_| StatusCode::BAD_GATEWAY)?;