//! Builder pattern for cluster creation use std::net::SocketAddr; use std::path::PathBuf; use std::sync::Arc; use chainfire_types::node::NodeRole; use chainfire_types::RaftRole; use crate::callbacks::{ClusterEventHandler, KvEventHandler}; use crate::cluster::Cluster; use crate::config::{ClusterConfig, MemberConfig, StorageBackendConfig, TimeoutConfig}; use crate::error::{ClusterError, Result}; use crate::events::EventDispatcher; /// Builder for creating a Chainfire cluster instance /// /// # Example /// /// ```ignore /// use chainfire_core::ClusterBuilder; /// /// let cluster = ClusterBuilder::new(1) /// .name("node-1") /// .gossip_addr("0.0.0.0:7946".parse()?) /// .raft_addr("0.0.0.0:2380".parse()?) /// .bootstrap(true) /// .build() /// .await?; /// ``` pub struct ClusterBuilder { config: ClusterConfig, cluster_handlers: Vec>, kv_handlers: Vec>, } impl ClusterBuilder { /// Create a new cluster builder with the given node ID pub fn new(node_id: u64) -> Self { Self { config: ClusterConfig { node_id, ..Default::default() }, cluster_handlers: Vec::new(), kv_handlers: Vec::new(), } } /// Set the node name pub fn name(mut self, name: impl Into) -> Self { self.config.node_name = name.into(); self } /// Set the node role (ControlPlane or Worker) pub fn role(mut self, role: NodeRole) -> Self { self.config.node_role = role; self } /// Set the Raft participation role (Voter, Learner, or None) pub fn raft_role(mut self, role: RaftRole) -> Self { self.config.raft_role = role; self } /// Set the API listen address pub fn api_addr(mut self, addr: SocketAddr) -> Self { self.config.api_addr = Some(addr); self } /// Set the Raft listen address (for control plane nodes) pub fn raft_addr(mut self, addr: SocketAddr) -> Self { self.config.raft_addr = Some(addr); self } /// Set the gossip listen address pub fn gossip_addr(mut self, addr: SocketAddr) -> Self { self.config.gossip_addr = addr; self } /// Set the storage backend pub fn storage(mut self, backend: StorageBackendConfig) -> Self { self.config.storage = backend; self } /// Set the data directory (convenience method for RocksDB storage) pub fn data_dir(mut self, path: impl Into) -> Self { self.config.storage = StorageBackendConfig::RocksDb { path: path.into() }; self } /// Use in-memory storage pub fn memory_storage(mut self) -> Self { self.config.storage = StorageBackendConfig::Memory; self } /// Add initial cluster members (for bootstrap) pub fn initial_members(mut self, members: Vec) -> Self { self.config.initial_members = members; self } /// Add a single initial member pub fn add_member(mut self, member: MemberConfig) -> Self { self.config.initial_members.push(member); self } /// Enable cluster bootstrap (first node) pub fn bootstrap(mut self, bootstrap: bool) -> Self { self.config.bootstrap = bootstrap; self } /// Set the cluster ID pub fn cluster_id(mut self, id: u64) -> Self { self.config.cluster_id = id; self } /// Enable gRPC API server pub fn with_grpc_api(mut self, enabled: bool) -> Self { self.config.enable_grpc_api = enabled; self } /// Set timeout configuration pub fn timeouts(mut self, timeouts: TimeoutConfig) -> Self { self.config.timeouts = timeouts; self } /// Register a cluster event handler /// /// Multiple handlers can be registered. They will all be called /// when cluster events occur. pub fn on_cluster_event(mut self, handler: H) -> Self where H: ClusterEventHandler + 'static, { self.cluster_handlers.push(Arc::new(handler)); self } /// Register a cluster event handler (Arc version) pub fn on_cluster_event_arc(mut self, handler: Arc) -> Self { self.cluster_handlers.push(handler); self } /// Register a KV event handler /// /// Multiple handlers can be registered. They will all be called /// when KV events occur. pub fn on_kv_event(mut self, handler: H) -> Self where H: KvEventHandler + 'static, { self.kv_handlers.push(Arc::new(handler)); self } /// Register a KV event handler (Arc version) pub fn on_kv_event_arc(mut self, handler: Arc) -> Self { self.kv_handlers.push(handler); self } /// Validate the configuration fn validate(&self) -> Result<()> { if self.config.node_id == 0 { return Err(ClusterError::Config("node_id must be non-zero".into())); } if self.config.node_name.is_empty() { return Err(ClusterError::Config("node_name is required".into())); } // Raft-participating nodes need a Raft address if self.config.raft_role.participates_in_raft() && self.config.raft_addr.is_none() { return Err(ClusterError::Config( "raft_addr is required for Raft-participating nodes".into(), )); } Ok(()) } /// Build the cluster instance /// /// This initializes the storage backend, Raft (if applicable), and gossip. pub async fn build(self) -> Result { self.validate()?; // Create event dispatcher with registered handlers let mut event_dispatcher = EventDispatcher::new(); for handler in self.cluster_handlers { event_dispatcher.add_cluster_handler(handler); } for handler in self.kv_handlers { event_dispatcher.add_kv_handler(handler); } // Create the cluster let cluster = Cluster::new(self.config, event_dispatcher); // TODO: Initialize storage backend // TODO: Initialize Raft if role participates // TODO: Initialize gossip // TODO: Start background tasks Ok(cluster) } }