#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(missing_docs)]
#![warn(clippy::all)]
pub use fortress_core;
use fortress_core::storage::InMemoryStorage;
use fortress_core::key::InMemoryKeyManager;
#[cfg(feature = "cli")]
pub use fortress_cli;
#[cfg(feature = "server")]
pub use fortress_api_server;
#[cfg(feature = "napi")]
pub use fortress_cli_napi;
pub mod prelude {
pub use fortress_core::prelude::*;
#[cfg(feature = "cli")]
pub use fortress_cli::{Commands, KeyAction, ConfigAction};
#[cfg(feature = "server")]
pub use fortress_api_server::prelude::{
ServerConfig, AuthManager, TokenClaims, HealthChecker,
MetricsCollector, AdvancedRateLimiter, RateLimitAlgorithm, RateLimitMetricsSnapshot,
FortressServer, GrpcServer, FortressGrpcService,
};
#[cfg(feature = "server")]
pub use fortress_api_server::models::HealthStatus;
}
pub struct FortressBuilder {
_private: (),
}
impl FortressBuilder {
pub fn new() -> Self {
Self { _private: () }
}
pub async fn build(self) -> Result<Fortress, Box<dyn std::error::Error>> {
Ok(Fortress::new().await?)
}
}
pub struct Fortress {
storage: std::sync::Arc<dyn fortress_core::storage::StorageBackend>,
key_manager: std::sync::Arc<InMemoryKeyManager>,
}
impl Fortress {
pub async fn new() -> Result<Self, Box<dyn std::error::Error>> {
let storage = std::sync::Arc::new(InMemoryStorage::new());
let key_manager = std::sync::Arc::new(InMemoryKeyManager::new());
Ok(Self { storage, key_manager })
}
pub fn builder() -> FortressBuilder {
FortressBuilder::new()
}
pub async fn create_database(&self, name: &str) -> Result<Database, Box<dyn std::error::Error>> {
Ok(Database {
name: name.to_string(),
storage: self.storage.clone(),
key_manager: self.key_manager.clone(),
})
}
}
pub struct Database {
#[allow(dead_code)]
name: String,
storage: std::sync::Arc<dyn fortress_core::storage::StorageBackend>,
#[allow(dead_code)]
key_manager: std::sync::Arc<InMemoryKeyManager>,
}
impl Database {
pub async fn insert(&self, table: &str, data: &serde_json::Value) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
let key = format!("{}/{}", table, uuid::Uuid::new_v4());
let serialized = serde_json::to_vec(data)?;
self.storage.put(&key, &serialized).await?;
let mut result = data.clone();
if let Some(obj) = result.as_object_mut() {
obj.insert("id".to_string(), serde_json::Value::String(key));
}
Ok(result)
}
pub async fn query(&self, table: &str, _filter: Option<&serde_json::Value>) -> Result<Vec<serde_json::Value>, Box<dyn std::error::Error>> {
let prefix = format!("{}/", table);
let keys = self.storage.list_prefix(&prefix).await?;
let mut results = Vec::new();
for key in keys {
if let Some(data) = self.storage.get(&key).await? {
if let Ok(value) = serde_json::from_slice::<serde_json::Value>(&data) {
results.push(value);
}
}
}
Ok(results)
}
pub async fn update(&self, table: &str, id: &str, data: &serde_json::Value) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
let key = format!("{}/{}", table, id);
let serialized = serde_json::to_vec(data)?;
self.storage.put(&key, &serialized).await?;
let mut result = data.clone();
if let Some(obj) = result.as_object_mut() {
obj.insert("id".to_string(), serde_json::Value::String(id.to_string()));
}
Ok(result)
}
pub async fn delete(&self, table: &str, id: &str) -> Result<bool, Box<dyn std::error::Error>> {
let key = format!("{}/{}", table, id);
self.storage.delete(&key).await?;
Ok(true)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_fortress_creation() {
let fortress = Fortress::new().await;
assert!(fortress.is_ok());
}
#[tokio::test]
async fn test_database_operations() {
let fortress = Fortress::new().await.unwrap();
let db = fortress.create_database("test").await;
assert!(db.is_ok());
}
}