use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ConnectionState {
Disconnected,
Connecting,
Connected,
Failed(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct Address {
pub transport_type: String,
pub address: String,
}
impl Address {
pub fn new(transport_type: impl Into<String>, address: impl Into<String>) -> Self {
Self {
transport_type: transport_type.into(),
address: address.into(),
}
}
pub fn http(address: impl Into<String>) -> Self {
Self::new("http", address)
}
pub fn iroh(node_id: impl Into<String>) -> Self {
Self::new("iroh", node_id)
}
pub fn from_node_addr(node_addr: &iroh::NodeAddr) -> Self {
Self::new("iroh", node_addr.node_id.to_string())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PeerInfo {
pub pubkey: String,
pub display_name: Option<String>,
pub first_seen: String,
pub last_seen: String,
pub status: PeerStatus,
pub addresses: Vec<Address>,
pub connection_state: ConnectionState,
pub last_successful_sync: Option<String>,
pub connection_attempts: u32,
pub last_error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub enum PeerStatus {
#[default]
Active,
Inactive,
Blocked,
}
impl PeerInfo {
pub fn new(pubkey: impl Into<String>, display_name: Option<&str>) -> Self {
let now = chrono::Utc::now().to_rfc3339();
Self {
pubkey: pubkey.into(),
display_name: display_name.map(|s| s.to_string()),
first_seen: now.clone(),
last_seen: now,
status: PeerStatus::Active,
addresses: Vec::new(),
connection_state: ConnectionState::Disconnected,
last_successful_sync: None,
connection_attempts: 0,
last_error: None,
}
}
pub fn touch(&mut self) {
self.last_seen = chrono::Utc::now().to_rfc3339();
}
pub fn add_address(&mut self, address: Address) {
if !self.addresses.contains(&address) {
self.addresses.push(address);
}
}
pub fn remove_address(&mut self, address: &Address) -> bool {
let initial_len = self.addresses.len();
self.addresses.retain(|a| a != address);
self.addresses.len() != initial_len
}
pub fn get_addresses(&self, transport_type: impl AsRef<str>) -> Vec<&Address> {
self.addresses
.iter()
.filter(|a| a.transport_type == transport_type.as_ref())
.collect()
}
pub fn get_all_addresses(&self) -> &Vec<Address> {
&self.addresses
}
pub fn has_transport(&self, transport_type: impl AsRef<str>) -> bool {
self.addresses
.iter()
.any(|a| a.transport_type == transport_type.as_ref())
}
}