use crate::NodeId;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::SocketAddr;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Member {
pub id: NodeId,
pub addr: SocketAddr,
pub state: MemberState,
pub metadata: HashMap<String, String>,
pub last_seen: chrono::DateTime<chrono::Utc>,
}
impl Member {
pub fn new(id: NodeId, addr: SocketAddr) -> Self {
Self {
id,
addr,
state: MemberState::Alive,
metadata: HashMap::new(),
last_seen: chrono::Utc::now(),
}
}
pub fn is_alive(&self) -> bool {
self.state == MemberState::Alive
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum MemberState {
Alive,
Suspect,
Dead,
Left,
}
impl MemberState {
pub fn as_str(&self) -> &'static str {
match self {
MemberState::Alive => "alive",
MemberState::Suspect => "suspect",
MemberState::Dead => "dead",
MemberState::Left => "left",
}
}
}
#[derive(Clone, Debug)]
pub enum MembershipEvent {
Joined(Member),
Left(NodeId),
StateChanged {
id: NodeId,
old: MemberState,
new: MemberState,
},
MetadataChanged {
id: NodeId,
key: String,
value: Option<String>,
},
}
#[derive(Clone, Debug)]
pub struct ClusterState {
pub local: Member,
pub members: Vec<Member>,
pub alive_count: usize,
}
impl ClusterState {
pub fn get_member(&self, id: &NodeId) -> Option<&Member> {
self.members.iter().find(|m| &m.id == id)
}
pub fn alive_members(&self) -> impl Iterator<Item = &Member> {
self.members.iter().filter(|m| m.is_alive())
}
}
#[derive(Clone, Debug)]
pub struct ClusterConfig {
pub bind_addr: SocketAddr,
pub seeds: Vec<SocketAddr>,
pub cluster_name: String,
pub gossip_interval: std::time::Duration,
pub failure_timeout: std::time::Duration,
pub metadata: std::collections::HashMap<String, String>,
}
impl Default for ClusterConfig {
fn default() -> Self {
Self {
bind_addr: "0.0.0.0:7000".parse().unwrap(),
seeds: Vec::new(),
cluster_name: "pollen".to_string(),
gossip_interval: std::time::Duration::from_millis(200),
failure_timeout: std::time::Duration::from_secs(5),
metadata: std::collections::HashMap::new(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_member_is_alive() {
let mut member = Member::new(NodeId::new(), "127.0.0.1:7000".parse().unwrap());
assert!(member.is_alive());
member.state = MemberState::Dead;
assert!(!member.is_alive());
}
#[test]
fn test_cluster_config_default() {
let config = ClusterConfig::default();
assert_eq!(config.cluster_name, "pollen");
assert!(config.seeds.is_empty());
}
}