use axum::{
Router,
routing::{get, post, put, delete},
Json,
};
use std::net::SocketAddr;
use std::sync::Arc;
use tower::ServiceBuilder;
use tower_http::{
cors::CorsLayer,
trace::TraceLayer,
compression::CompressionLayer,
};
use tracing::info;
use fortress_api_server::handlers::{
get_tenant_stats, admin_list_data, create_openapi, AppState,
detailed_health_check, security_health_check,
get_prometheus_metrics, get_security_events, get_blocked_requests,
store_data, retrieve_data, update_data, delete_data, list_data,
generate_key, create_tenant, list_tenants
};
use fortress_api_server::auth::{AuthManager, InMemoryUserStore};
use fortress_api_server::metrics::MetricsCollector;
use fortress_api_server::health::HealthChecker;
use fortress_api_server::graphql::{graphql_handler, graphql_playground};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
info!("Fortress server starting");
let openapi = create_openapi();
let app = create_router(openapi).await?;
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
info!("Fortress server listening on {}", addr);
let listener = tokio::net::TcpListener::bind(addr).await?;
axum::serve(listener, app).await?;
Ok(())
}
async fn create_router(_openapi: utoipa::openapi::OpenApi) -> Result<Router, Box<dyn std::error::Error>> {
let state = create_app_state().await?;
let app = Router::new()
.route("/health", get(health_check))
.route("/health/detailed", get(detailed_health_check))
.route("/health/security", get(security_health_check))
.route("/openapi.json", get(openapi_handler))
.route("/metrics", get(get_prometheus_metrics))
.route("/security/events", get(get_security_events))
.route("/security/blocked-requests", get(get_blocked_requests))
.route("/graphql", get(graphql_handler).post(graphql_handler))
.route("/graphql/playground", get(graphql_playground))
.route("/api/v1/data", post(store_data))
.route("/api/v1/data/:key", get(retrieve_data))
.route("/api/v1/data/:key", put(update_data))
.route("/api/v1/data/:key", delete(delete_data))
.route("/api/v1/data", get(list_data))
.route("/api/v1/keys", post(generate_key))
.route("/api/v1/tenants", post(create_tenant))
.route("/api/v1/tenants", get(list_tenants))
.route("/api/v1/tenants/:tenant_id/stats", get(get_tenant_stats))
.route("/api/v1/admin/data", get(admin_list_data))
.layer(
ServiceBuilder::new()
.layer(TraceLayer::new_for_http())
.layer(CompressionLayer::new())
.layer(CorsLayer::permissive())
)
.with_state(state);
Ok(app)
}
async fn create_app_state() -> Result<Arc<AppState>, Box<dyn std::error::Error>> {
use fortress_api_server::handlers::AppState;
use fortress_core::tenant::{InMemoryTenantManager, GlobalResourceLimits};
use fortress_api_server::config::FeatureFlags;
use fortress_core::field_encryption_manager::DefaultFieldEncryptionManager;
use chrono::Duration;
let auth_manager = Arc::new(AuthManager::new(
"demo-jwt-secret",
Duration::seconds(3600),
Arc::new(InMemoryUserStore::new())
));
let metrics = Arc::new(MetricsCollector::new());
let key_manager = Arc::new(fortress_core::key::InMemoryKeyManager::new());
let storage = Arc::new(fortress_core::storage::FileSystemStorage::new("./data")?);
let field_encryption_manager = Arc::new(
DefaultFieldEncryptionManager::new(key_manager.clone())
);
let health_checker = Arc::new(HealthChecker::new(
FeatureFlags::default()
));
let global_limits = GlobalResourceLimits {
max_total_databases: Some(100),
max_total_storage: Some(10737418240), max_total_connections: Some(1000),
max_total_cpu: Some(80.0),
max_total_memory: Some(80.0),
};
let tenant_manager = Arc::new(InMemoryTenantManager::with_global_limits(global_limits));
let dynamic_secrets = Arc::new(fortress_core::dynamic_secrets::DynamicSecretsEngine::new());
let state = AppState {
auth_manager,
metrics,
key_manager,
field_encryption_manager,
storage,
health_checker,
tenant_manager,
dynamic_secrets,
};
Ok(Arc::new(state))
}
async fn health_check() -> Json<serde_json::Value> {
Json(serde_json::json!({
"status": "healthy",
"timestamp": chrono::Utc::now(),
"version": "0.1.0"
}))
}
async fn openapi_handler() -> Json<utoipa::openapi::OpenApi> {
Json(create_openapi())
}