photoncloud-monorepo/deployer/crates/deployer-server/src/state.rs

118 lines
3.7 KiB
Rust

use deployer_types::NodeInfo;
use std::collections::HashMap;
use tokio::sync::{Mutex, RwLock};
use tracing::{info, warn};
use crate::config::Config;
use crate::local_storage::LocalStorage;
use crate::storage::NodeStorage;
/// Application state shared across handlers
pub struct AppState {
/// Server configuration
pub config: Config,
/// ChainFire-backed storage (when available)
pub storage: Option<Mutex<NodeStorage>>,
/// Local file-backed storage (when configured)
pub local_storage: Option<Mutex<LocalStorage>>,
/// Fallback in-memory node registry
/// Key: node_id, Value: NodeInfo
pub nodes: RwLock<HashMap<String, NodeInfo>>,
/// Fallback in-memory machine_id → (node_id, NodeConfig) mapping
pub machine_configs: RwLock<HashMap<String, (String, deployer_types::NodeConfig)>>,
}
impl AppState {
/// Create new application state with default config
pub fn new() -> Self {
Self::with_config(Config::default())
}
/// Create application state with custom config
pub fn with_config(config: Config) -> Self {
Self {
config,
storage: None,
local_storage: None,
nodes: RwLock::new(HashMap::new()),
machine_configs: RwLock::new(HashMap::new()),
}
}
/// Initialize ChainFire storage connection
pub async fn init_storage(&mut self) -> anyhow::Result<()> {
if let Some(path) = self.config.local_state_path.clone() {
match LocalStorage::open(path) {
Ok(storage) => {
info!("Local storage initialized for Deployer bootstrapper");
self.local_storage = Some(Mutex::new(storage));
}
Err(e) => {
warn!(error = %e, "Failed to initialize local storage");
}
}
}
if self.config.chainfire.endpoints.is_empty() {
if self.config.require_chainfire {
return Err(anyhow::anyhow!(
"No ChainFire endpoints configured while require_chainfire=true"
));
}
warn!("No ChainFire endpoints configured, using in-memory storage");
return Ok(());
}
let namespace = &self.config.chainfire.namespace;
for endpoint in &self.config.chainfire.endpoints {
match NodeStorage::connect(endpoint, namespace).await {
Ok(storage) => {
info!(
endpoint = %endpoint,
namespace = %namespace,
"Connected to ChainFire storage"
);
self.storage = Some(Mutex::new(storage));
return Ok(());
}
Err(e) => {
warn!(
endpoint = %endpoint,
error = %e,
"Failed to connect to ChainFire endpoint"
);
}
}
}
if self.config.require_chainfire {
Err(anyhow::anyhow!(
"Failed to connect to any ChainFire endpoints and require_chainfire=true"
))
} else {
warn!("Failed to connect to any ChainFire endpoints, using in-memory storage");
Ok(())
}
}
/// Check if ChainFire storage is available
pub fn has_storage(&self) -> bool {
self.storage.is_some()
}
/// Check if local storage is available
pub fn has_local_storage(&self) -> bool {
self.local_storage.is_some()
}
}
impl Default for AppState {
fn default() -> Self {
Self::new()
}
}