use std::sync::Arc;
use crate::agent::ToolRegistry;
use crate::config::{AppConfig, ConfigError};
use crate::thingd::{MemoryThingdBackend, ThingdBackend};
#[derive(Clone)]
pub struct AppState {
pub config: AppConfig,
pub storage: Arc<dyn ThingdBackend>,
pub tool_registry: Arc<ToolRegistry>,
}
impl AppState {
pub fn builder() -> AppStateBuilder {
AppStateBuilder::new()
}
}
pub struct AppStateBuilder {
config: Option<AppConfig>,
storage: Option<Arc<dyn ThingdBackend>>,
tool_registry: Option<Arc<ToolRegistry>>,
}
impl AppStateBuilder {
pub fn new() -> Self {
Self {
config: None,
storage: None,
tool_registry: None,
}
}
pub fn with_config(mut self, config: AppConfig) -> Self {
self.config = Some(config);
self
}
pub fn with_storage(mut self, storage: Arc<dyn ThingdBackend>) -> Self {
self.storage = Some(storage);
self
}
pub fn with_tool_registry(mut self, registry: ToolRegistry) -> Self {
self.tool_registry = Some(Arc::new(registry));
self
}
pub fn build(self) -> Result<AppState, ConfigError> {
let config = self.config.unwrap_or_default();
let storage = self.storage.unwrap_or_else(|| {
Arc::new(MemoryThingdBackend::new())
});
let tool_registry = self.tool_registry.unwrap_or_else(|| {
Arc::new(ToolRegistry::new(
&format!("{}-app", env!("CARGO_PKG_NAME")),
env!("CARGO_PKG_VERSION"),
"An Arqen application",
&format!("{:?}", config.storage.mode),
))
});
Ok(AppState {
config,
storage,
tool_registry,
})
}
}
impl Default for AppStateBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::StorageMode;
#[test]
fn test_app_state_builder_defaults() {
let state = AppState::builder().build().unwrap();
assert_eq!(state.config.server.port, 3000);
assert_eq!(state.config.storage.mode, StorageMode::Memory);
}
#[test]
fn test_app_state_builder_with_config() {
let config = AppConfig {
server: crate::config::ServerConfig {
port: 8080,
..Default::default()
},
..Default::default()
};
let state = AppState::builder()
.with_config(config)
.build()
.unwrap();
assert_eq!(state.config.server.port, 8080);
}
#[tokio::test]
async fn test_app_state_builder_with_storage() {
let storage = Arc::new(MemoryThingdBackend::new());
let state = AppState::builder()
.with_storage(storage)
.build()
.unwrap();
assert!(state.storage.count_objects("test").await.is_ok());
}
#[tokio::test]
async fn test_app_state_builder_with_registry() {
let registry = ToolRegistry::new("test-app", "1.0.0", "Test", "memory");
let state = AppState::builder()
.with_tool_registry(registry)
.build()
.unwrap();
assert_eq!(state.tool_registry.generate_manifest().name, "test-app");
}
}