Start scaffolding hosting applications

This commit is contained in:
Matt Gibson 2025-11-04 09:14:25 -08:00
parent ab1eaddb18
commit f2136bb809
No known key found for this signature in database
13 changed files with 241 additions and 11 deletions

29
akd/Cargo.lock generated
View File

@ -26,6 +26,19 @@ dependencies = [
"memchr",
]
[[package]]
name = "aio"
version = "0.1.0"
dependencies = [
"akd_storage",
"common",
"publisher",
"reader",
"tokio",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "akd"
version = "0.11.0"
@ -1476,8 +1489,11 @@ dependencies = [
name = "publisher"
version = "0.1.0"
dependencies = [
"akd",
"akd_storage",
"async-std",
"bitwarden-akd-configuration",
"common",
"tiberius",
"tokio",
"tokio-util",
@ -1530,6 +1546,19 @@ dependencies = [
"getrandom 0.2.16",
]
[[package]]
name = "reader"
version = "0.1.0"
dependencies = [
"akd",
"akd_storage",
"bitwarden-akd-configuration",
"common",
"tokio",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "redox_syscall"
version = "0.5.17"

View File

@ -16,6 +16,9 @@ unwrap_used = "deny"
[workspace.dependencies]
akd = "0.11.0"
async-trait = "0.1.89"
akd_storage = { path = "crates/akd_storage" }
bitwarden-akd-configuration = { path = "crates/bitwarden-akd-configuration" }
common = { path = "crates/common" }
config = "0.15.18"
serde = { version = "1.0.228", features = ["derive"] }
tokio = { version = "1.47.1", features = ["full"] }

19
akd/crates/aio/Cargo.toml Normal file
View File

@ -0,0 +1,19 @@
[package]
name = "aio"
edition.workspace = true
version.workspace = true
authors.workspace = true
license-file.workspace = true
keywords.workspace = true
[dependencies]
akd_storage = { workspace = true }
common = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
tokio = { workspace = true }
publisher = { path = "../publisher" }
reader = { path = "../reader" }
[lints]
workspace = true

View File

@ -0,0 +1,41 @@
//! AIO process for an AKD. Spins up multiple async tasks to handle publisher and reader roles.
//! Requires both read and write permissions to the underlying data stores.
//! There should only be one instance of this running at a time for a given AKD.
use akd_storage::db_config::DbConfig;
use common::VrfStorageType;
#[tokio::main]
async fn main() {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::TRACE)
.init();
let connection_string = std::env::var("AKD_MSSQL_CONNECTION_STRING")
.expect("AKD_MSSQL_CONNECTION_STRING must be set.");
let db_config = DbConfig::MsSql {
connection_string,
pool_size: 10,
};
let db = db_config
.connect()
.await
.expect("Failed to connect to database");
let vrf = VrfStorageType::HardCodedAkdVRF;
// Start the publisher write job
let _write_job_handle = {
let db = db.clone();
let vrf = vrf.clone();
tokio::spawn(async move {
publisher::start_write_job(db, vrf).await;
})
};
// Create a router with both publisher and reader routes
todo!();
// Start the web server
todo!();
}

View File

@ -21,6 +21,8 @@ mod temp_table;
pub mod akd_storage_config;
pub mod db_config;
/// Enum to represent different database types supported by the storage layer.
/// Each variant is cheap to clone for reuse across threads.
#[derive(Debug, Clone)]
pub enum DatabaseType {
MsSql(MsSql),

View File

@ -12,7 +12,7 @@ path = "src/main.rs"
[dependencies]
akd = { workspace = true }
akd_storage = { path = "../akd_storage" }
akd_storage = { workspace = true}
anyhow = "1"
async-trait = { workspace = true }
clap = { version = "4", features = ["derive"] }

View File

@ -9,7 +9,7 @@ keywords.workspace = true
[dependencies]
akd = "0.11.0"
async-trait = { workspace = true }
akd_storage = { path = "../akd_storage" }
akd_storage = { workspace = true}
config = { workspace = true }
serde = { workspace = true }
thiserror = "2.0.17"

View File

@ -7,7 +7,10 @@ license-file.workspace = true
keywords.workspace = true
[dependencies]
akd_storage = { path = "../akd_storage" }
akd = { workspace = true }
akd_storage = { workspace = true}
bitwarden-akd-configuration = { workspace = true}
common = { workspace = true }
tokio-util = {version = "0.7.16", features = ["compat"] }
tokio = { workspace = true }
tracing = { workspace = true }

View File

@ -0,0 +1,22 @@
use akd::{directory::Directory, storage::StorageManager};
use akd_storage::DatabaseType;
use bitwarden_akd_configuration::BitwardenV1Configuration;
use common::VrfStorageType;
use tracing::instrument;
struct AppState {
directory: Directory<BitwardenV1Configuration, DatabaseType, VrfStorageType>,
}
#[instrument(skip_all, name = "publisher_start")]
pub async fn start_write_job(_db: DatabaseType, vrf: VrfStorageType) {
let storage_manager = StorageManager::new_no_cache(_db);
let _app_state = AppState {
directory: Directory::new(storage_manager, vrf).await.unwrap(),
};
println!("Publisher started");
}
pub async fn start_web_server(_db: DatabaseType) {
println!("Web server started");
}

View File

@ -1,17 +1,48 @@
//! The Publisher crate is responsible for tracking insert requests into the AKD and performing them as batches on a schedule.
//! Write permissions are needed to the underlying data stores.
//! There should only be one instance of this running at a time for a given AKD.
use akd_storage::db_config::DbConfig;
use publisher::{start_web_server, start_write_job};
use tracing::info;
#[tokio::main]
async fn main() {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::TRACE)
.init();
.with_max_level(tracing::Level::TRACE)
.init();
// Read connection string from env var
let connection_string = std::env::var("AKD_MSSQL_CONNECTION_STRING").expect("AKD_MSSQL_CONNECTION_STRING must be set.");
let connection_string = std::env::var("AKD_MSSQL_CONNECTION_STRING")
.expect("AKD_MSSQL_CONNECTION_STRING must be set.");
let db_config = DbConfig::MsSql {
connection_string,
pool_size: 10,
};
let mssql = akd_storage::ms_sql::MsSql::builder(connection_string)
.pool_size(10)
.build()
let db = db_config
.connect()
.await
.expect("Failed to create MsSql instance");
.expect("Failed to connect to database");
let vrf = common::VrfStorageType::HardCodedAkdVRF;
mssql.migrate().await.expect("Failed to run migrations");
let write_job_handle = {
let db = db.clone();
tokio::spawn(async move {
start_write_job(db, vrf).await;
})
};
let web_server_handle = tokio::spawn(async move {
start_web_server(db).await;
});
// Wait for both services to complete
tokio::select! {
_ = write_job_handle => {
info!("Write job completed");
}
_ = web_server_handle => {
info!("Web service completed");
}
}
}

View File

@ -0,0 +1,19 @@
[package]
name = "reader"
edition.workspace = true
version.workspace = true
authors.workspace = true
license-file.workspace = true
keywords.workspace = true
[dependencies]
tokio = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
akd = { workspace = true }
akd_storage = { workspace = true}
bitwarden-akd-configuration = { workspace = true}
common = { workspace = true}
[lints]
workspace = true

View File

@ -0,0 +1,21 @@
use std::sync::Arc;
use akd::{directory::ReadOnlyDirectory, storage::StorageManager};
use tracing::instrument;
use bitwarden_akd_configuration::BitwardenV1Configuration;
use akd_storage::DatabaseType;
use common::VrfStorageType;
struct AppState {
// Add any shared state here, e.g., database connections
directory: ReadOnlyDirectory<BitwardenV1Configuration, DatabaseType, VrfStorageType>,
}
#[instrument(skip_all, name = "reader_start")]
pub async fn start(db: DatabaseType, vrf: VrfStorageType) {
let storage_manager = StorageManager::new_no_cache(db);
let _app = AppState {
directory: ReadOnlyDirectory::new(storage_manager, vrf).await.unwrap(),
};
println!("Reader started");
}

View File

@ -0,0 +1,40 @@
//! The Reader crate is responsible for handling read requests to the AKD. It requires only read permissions to the
//! underlying data stores, and can be horizontally scaled as needed.
use akd::ecvrf::VRFKeyStorage;
use akd_storage::db_config::DbConfig;
use common::VrfStorageType;
use reader::start;
use tracing::info;
#[tokio::main]
async fn main() {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::TRACE)
.init();
// Read connection string from env var
let connection_string = std::env::var("AKD_MSSQL_CONNECTION_STRING")
.expect("AKD_MSSQL_CONNECTION_STRING must be set.");
let db_config = DbConfig::MsSql {
connection_string,
pool_size: 10,
};
let db = db_config
.connect()
.await
.expect("Failed to connect to database");
let vrf = VrfStorageType::HardCodedAkdVRF;
let web_server_handle = tokio::spawn(async move {
start(db, vrf).await;
});
// Wait for both services to complete
tokio::select! {
_ = web_server_handle => {
info!("Web service completed");
}
}
}