use d_engine_proto::common::NodeRole;
use crate::Membership;
use crate::TypeConfig;
pub fn role_emoji(role: i32) -> &'static str {
use d_engine_proto::common::NodeRole;
match role {
r if r == NodeRole::Follower as i32 => "๐ฎ",
r if r == NodeRole::Candidate as i32 => "๐ณ๏ธ",
r if r == NodeRole::Leader as i32 => "๐",
r if r == NodeRole::Learner as i32 => "๐",
_ => "โ", }
}
pub fn role_name(role: i32) -> &'static str {
use d_engine_proto::common::NodeRole;
match role {
r if r == NodeRole::Follower as i32 => "Follower",
r if r == NodeRole::Candidate as i32 => "Candidate",
r if r == NodeRole::Leader as i32 => "Leader",
r if r == NodeRole::Learner as i32 => "Learner",
_ => "Unknown",
}
}
pub fn status_emoji(status: i32) -> &'static str {
use d_engine_proto::common::NodeStatus;
match status {
s if s == NodeStatus::Unspecified as i32 => "โ", s if s == NodeStatus::Promotable as i32 => "๐", s if s == NodeStatus::ReadOnly as i32 => "๐", s if s == NodeStatus::Active as i32 => "โ
", _ => "โ",
}
}
pub fn status_name(status: i32) -> &'static str {
use d_engine_proto::common::NodeStatus;
match status {
s if s == NodeStatus::Unspecified as i32 => "Unspecified",
s if s == NodeStatus::Promotable as i32 => "Promotable",
s if s == NodeStatus::ReadOnly as i32 => "ReadOnly",
s if s == NodeStatus::Active as i32 => "Active",
_ => "Unknown",
}
}
pub async fn print_cluster_membership_table<T: TypeConfig, M: Membership<T>>(membership: &M) {
let members = membership.get_all_nodes().await;
println!("\n{}", "=".repeat(80));
println!(" CLUSTER MEMBERSHIP:");
println!(
" {:<8} {:<20} {:<18} {:<15}",
"Node ID", "Address", "Role", "Status"
);
println!(" {}", "-".repeat(80));
for member in members {
println!(
" {:<8} {:<20} {:<18} {:<15}",
member.id,
member.address,
format!("{} {}", role_emoji(member.role), role_name(member.role)),
format!(
"{} {}",
status_emoji(member.status),
status_name(member.status)
)
);
}
println!("{}", "=".repeat(80));
}
pub async fn print_node_startup_banner<T: TypeConfig, M: Membership<T>>(
node_id: u32,
listen_addr: &str,
current_role: i32,
current_term: u64,
leader_id: Option<u32>,
membership: &M,
) {
println!("\n{}", "=".repeat(80));
println!(" D-ENGINE NODE STARTED");
println!("{}", "=".repeat(80));
println!(" Node ID: {node_id}");
println!(" Listen Address: {listen_addr}");
println!(
" Current Role: {} {}",
role_emoji(current_role),
role_name(current_role)
);
println!(" Current Term: {current_term}");
println!(
" Leader ID: {}",
leader_id.map(|id| id.to_string()).unwrap_or_else(|| "None".to_string())
);
println!("{}", "=".repeat(80));
print_cluster_membership_table(membership).await;
}
pub fn print_learner_join_success(
node_id: u32,
leader_id: u32,
) {
println!("\n{}", "๐".repeat(40));
println!(" โ
NODE {node_id} SUCCESSFULLY JOINED CLUSTER");
println!(
" Role: {} Learner โ Syncing data from Leader {leader_id}",
role_emoji(NodeRole::Learner as i32)
);
println!(" Next: Will auto-promote to Voter when caught up (if Promotable status)");
println!("{}\n", "๐".repeat(40));
}
pub fn print_learner_promoted_to_voter(node_id: u32) {
println!("\n{}", "๐".repeat(40));
println!(" ๐ NODE {node_id} PROMOTED TO VOTER!");
println!(
" Old Role: {} Learner",
role_emoji(NodeRole::Learner as i32)
);
println!(
" New Role: {} Follower (Voter)",
role_emoji(NodeRole::Follower as i32)
);
println!(" Status: Can now participate in voting and consensus");
println!("{}\n", "๐".repeat(40));
}
pub fn print_role_transition(
node_id: u32,
from_role: i32,
to_role: i32,
term: u64,
reason: &str,
) {
println!("\n{}", "=".repeat(80));
println!(" ๐ ROLE TRANSITION");
println!("{}", "=".repeat(80));
println!(" Node ID: {node_id}");
println!(
" From Role: {} {}",
role_emoji(from_role),
role_name(from_role)
);
println!(
" To Role: {} {}",
role_emoji(to_role),
role_name(to_role)
);
println!(" Term: {term}");
println!(" Reason: {reason}");
println!("{}", "=".repeat(80));
}
pub fn print_leader_accepting_new_node(
leader_id: u32,
new_node_id: u32,
new_node_addr: &str,
role: i32,
) {
println!("\n{}", "=".repeat(80));
println!(" โ
LEADER: ACCEPTING NEW NODE");
println!("{}", "=".repeat(80));
println!(" Leader ID: {leader_id}");
println!(" New Node ID: {new_node_id}");
println!(" New Node Addr: {new_node_addr}");
println!(
" Role: {} {}",
role_emoji(role),
role_name(role)
);
println!(" Action: AddNode config change committed");
println!("{}", "=".repeat(80));
}
pub fn print_leader_promoting_learner(
leader_id: u32,
learner_id: u32,
match_index: u64,
commit_index: u64,
) {
let progress = if commit_index > 0 {
(match_index as f64 / commit_index as f64) * 100.0
} else {
100.0
};
println!("\n{}", "=".repeat(80));
println!(" ๐ LEADER: PROMOTING LEARNER");
println!("{}", "=".repeat(80));
println!(" Leader ID: {leader_id}");
println!(" Learner ID: {learner_id}");
println!(" Learner Match Index: {match_index}");
println!(" Leader Commit Index: {commit_index}");
println!(" Progress: {progress:.1}%");
println!(" Action: Scheduling PromoteToVoter config change");
println!("{}", "=".repeat(80));
}