use crate::config::Config;
use crate::error::{Error, Result};
use crate::node::RaftNode;
use openraft::Config as OpenRaftConfig;
use std::sync::Arc;
use tracing::info;
pub struct RaftNodeBuilder<'a> {
config: Option<&'a Config>,
auto_init_cluster: bool,
grpc_timeout_seconds: u64,
max_client_pool_size: usize,
raft_config: Option<OpenRaftConfig>,
}
impl<'a> Default for RaftNodeBuilder<'a> {
fn default() -> Self {
Self {
config: None,
auto_init_cluster: true,
grpc_timeout_seconds: 10,
max_client_pool_size: 10,
raft_config: None,
}
}
}
impl<'a> RaftNodeBuilder<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn config(mut self, config: &'a Config) -> Self {
self.config = Some(config);
self
}
pub fn auto_init_cluster(mut self, auto_init: bool) -> Self {
self.auto_init_cluster = auto_init;
self
}
pub fn grpc_timeout_seconds(mut self, seconds: u64) -> Self {
self.grpc_timeout_seconds = seconds;
self
}
pub fn max_client_pool_size(mut self, size: usize) -> Self {
self.max_client_pool_size = size;
self
}
pub fn raft_config(mut self, config: OpenRaftConfig) -> Self {
self.raft_config = Some(config);
self
}
fn validate(&self) -> Result<()> {
if self.config.is_none() {
return Err(Error::config(
"Config is required. Use .config() to provide one.",
));
}
if self.grpc_timeout_seconds == 0 {
return Err(Error::config("grpc_timeout_seconds must be > 0"));
}
if self.max_client_pool_size == 0 {
return Err(Error::config("max_client_pool_size must be > 0"));
}
Ok(())
}
pub async fn build(self) -> Result<Arc<RaftNode>> {
self.validate()?;
let config = self
.config
.ok_or_else(|| Error::config("Config is required. Use .config() to provide one."))?;
info!("Building RaftNode with node_id={}", config.node_id);
let raft_node = RaftNode::create(config).await?;
RaftNode::start_raft_service(raft_node.clone()).await?;
if self.auto_init_cluster {
if config.raft.single {
info!("Initializing single-node cluster");
let node = crate::raft::types::Node {
node_id: config.node_id,
endpoint: config.raft.endpoint.clone(),
};
raft_node.init_cluster(node).await?;
} else if !config.raft.join.is_empty() {
info!("Joining existing cluster via: {:?}", config.raft.join);
raft_node.join_cluster().await?;
} else {
info!("Auto-init skipped: no join list and not in single mode");
}
} else {
info!("Auto-init disabled: node will not join cluster automatically");
}
info!("RaftNode built successfully");
Ok(raft_node)
}
}
impl<'a> RaftNodeBuilder<'a> {
pub async fn from_config(config: &'a Config) -> Result<Arc<RaftNode>> {
Self::new().config(config).build().await
}
pub async fn standalone(config: &'a Config) -> Result<Arc<RaftNode>> {
Self::new()
.config(config)
.auto_init_cluster(false)
.build()
.await
}
}