use std::collections::HashMap;
use conciliator::{
Print,
Color,
Paint,
Conciliator
};
use serde::{Serialize, Deserialize};
use crate::event;
use crate::message;
use crate::net::{
InterfaceAddress,
interface::InterfaceLauncher
};
use crate::peer::{
Address,
Invitation,
Status,
};
use crate::peer::link::{
Link,
LinkState
};
use crate::util::*;
use super::{
KeyArg,
NodeArg,
NodeIDArg
};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CnsprcyStatus {
pub id: NodeIDArg,
pub name: String,
pub addrs: Vec<InterfaceAddress>,
pub handlers: Vec<String>,
pub conspirators: Vec<Conspirator>
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Conspirator {
pub id: NodeIDArg,
pub name: String,
pub state: Status,
pub link: Option<Link>
}
#[derive(Debug)]
pub struct NodeJoinRequest {
pub id: NodeIDArg,
pub name: String,
pub addr: Address
}
#[derive(Debug)]
pub enum AnyRequest {
Daemon(DaemonReq),
Node(NodeReq),
Mirror(MirrorReq),
Router(RouterReq),
Dispatcher(DispatcherReq)
}
#[derive(Debug)]
pub enum DaemonReq {
GetStatus(
GetRequest<CnsprcyStatus>
),
StopServer(
GetRequest<bool>
),
Invite(
Request<KeyArg, Invitation>
),
Accept(
Request<Invitation, bool>
)
}
#[derive(Debug)]
pub enum NodeReq {
Write(
Request<(String, String), bool>
),
AddAddress(
Request<(NodeArg, Address), bool>
),
Advertise(
GetRequest<KeyArg>
),
Invite(
Request<(KeyArg, Vec<Address>), Invitation>
),
Disable(
Request<NodeArg, bool>
),
Join(
Request<NodeJoinRequest, bool>
),
GetConspirator(
Request<NodeArg, Conspirator>
),
GetConspirators(
GetRequest<Vec<Conspirator>>
),
SendPayload(
Request<(NodeArg, message::Payload, Option<Address>), bool>
),
GetStatus(
Request<(Vec<InterfaceAddress>, Vec<String>), CnsprcyStatus>
)
}
#[derive(Debug)]
pub enum DispatcherReq {
GetHandlers(
GetRequest<Vec<String>>
),
Dispatch(
Request<event::DynamicEvent, bool>
),
}
#[derive(Debug)]
pub enum RouterReq {
GetInterfaces(
GetRequest<Vec<InterfaceAddress>>
),
CanSend(
Request<Address, bool>
),
BindInterface(
Request<InterfaceAddress, bool>
),
LaunchInterface(
Request<InterfaceLauncher, bool>
),
Rekey(
Request<KeyArg, bool>
),
RemoveInterface(
Request<Address, bool>
)
}
#[derive(Debug)]
pub enum MirrorReq {
Enable(Request<String, bool>),
Disable(Request<String, bool>),
}
impl From<DaemonReq> for AnyRequest {
fn from(req: DaemonReq) -> Self {Self::Daemon(req)}
}
impl From<NodeReq> for AnyRequest {
fn from(req: NodeReq) -> Self {Self::Node(req)}
}
impl From<MirrorReq> for AnyRequest {
fn from(req: MirrorReq) -> Self {Self::Mirror(req)}
}
impl From<RouterReq> for AnyRequest {
fn from(req: RouterReq) -> Self {Self::Router(req)}
}
impl From<DispatcherReq> for AnyRequest {
fn from(req: DispatcherReq) -> Self {Self::Dispatcher(req)}
}
impl Print for &Conspirator {
fn print<C: Conciliator + ?Sized>(self, con: &C) {
let mut buffer = con.get_line();
buffer
.push_bold("[")
.push_omega_bold(&self.id)
.push_bold("]")
.push(' ')
.push_alpha(&format_args!("{:<9}", &self.name))
.push(' ');
if self.link.is_none() && self.state == Status::Unreachable {
buffer.push_iota_bold("offline");
}
else {
buffer.push_beta_bold(&format_args!("{:^11?} ", self.state));
if let Some(link) = self.link.as_ref() {
if let Some(seen) = link.seen {
buffer
.push("\n ")
.push_omega(tree::KNOT)
.push("seen ");
push_time(&mut buffer, seen);
}
if let LinkState::BeenPinged(_) = link.state {
if let Some(pinged) = link.pinged {
buffer
.push("\n ")
.push_omega(tree::KNOT)
.push("pinged ");
push_time(&mut buffer, pinged);
}
}
buffer
.push("\n ")
.push_omega(tree::TAIL)
.push(link.address);
}
}
}
}
impl Print for &CnsprcyStatus {
fn print<C: Conciliator + ?Sized>(self, con: &C) {
let CnsprcyStatus {id, name, addrs, handlers, conspirators} = self;
let tag_color = match addrs.is_empty() {
true => Color::Iota,
false => Color::Alpha,
};
let mut header = con.get_line();
header
.tag(tag_color, "CNSPRCY")
.push('\t')
.push_alpha(name)
.push('\t')
.push_bold("[")
.push_omega_bold(id)
.push_bold("]");
drop(header);
let mut named: HashMap<&str, Vec<&InterfaceAddress>> = HashMap::new();
let mut unnamed = Vec::new();
for addr in addrs {
if let Some(name) = addr.get_name() {
named.entry(name)
.or_default()
.push(addr);
}
else {
unnamed.push(addr)
};
}
let last_idx = unnamed.is_empty().then_some(
named.len().saturating_sub(1)
);
for (i, (name, addrs)) in named.into_iter().enumerate() {
con.get_line()
.push(" ")
.push_omega(
if last_idx == Some(i) {tree::TAIL} else {tree::KNOT}
)
.push_zeta_bold(name);
for (j, addr) in addrs.iter().enumerate() {
let Some(ip) = addr.get_socket_address().map(|a| a.ip()) else {
continue;
};
con.get_line()
.push(" ")
.push_omega(
if last_idx == Some(i) {" "} else {tree::STEM}
)
.push_omega(
if j == addrs.len() - 1 {tree::TAIL} else {tree::KNOT}
)
.push_beta(&ip);
}
}
match &unnamed[..] {
[] if addrs.is_empty() => {
con.get_line()
.push(" ")
.push_omega(tree::TAIL)
.push("< no interfaces >");
},
[] => {},
[addrs @ .., last] => {
for addr in addrs {
con.get_line()
.push(" ")
.push_omega(tree::KNOT)
.push(addr);
}
con.get_line()
.push(" ")
.push_omega(tree::TAIL)
.push(last);
}
}
for c in conspirators {
c.print(con);
}
match &handlers[..] {
[] => {
con.get_line().push("No event handlers registered");
},
[handlers @ .., last] => {
con.get_line().push("Event handlers:");
for handler in handlers {
con.get_line()
.push(" ")
.push_omega(tree::KNOT)
.push(handler);
}
con.get_line()
.push(" ")
.push_omega(tree::TAIL)
.push(last);
}
}
}
}