mod carrier_refusals;
use serde::Serialize;
use super::error::ConsoleError;
pub const RECORD_VERSION: u64 = 1;
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct Device {
pub id: String,
pub name: String,
pub kind: DeviceKind,
#[serde(skip_serializing_if = "Option::is_none")]
pub liminal: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub started: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub started_fault: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent: Option<String>,
#[serde(rename = "box", skip_serializing_if = "Option::is_none")]
pub zone: Option<DeviceBox>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
pub struct DeviceBox {
pub x: i64,
pub y: i64,
pub w: i64,
pub h: i64,
}
impl DeviceBox {
pub const THIS: Self = Self {
x: -140,
y: 60,
w: 1340,
h: 520,
};
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum DeviceKind {
Device,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct Station {
pub id: String,
pub name: String,
pub device: String,
pub kind: StationKind,
pub state: StationState,
#[serde(skip_serializing_if = "Option::is_none")]
pub subjects: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub activities: Option<Vec<StationActivity>>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct StationActivity {
pub name: String,
pub input_schema_json: String,
pub output_schema_json: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum StationKind {
Service,
Worker,
Depot,
Exchange,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum StationState {
Live,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct Line {
pub id: String,
pub kind: LineKind,
pub life: LineLife,
pub state: LineState,
pub stops: Vec<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum LineKind {
Stream,
Call,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum LineLife {
Passing,
Kept,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum LineState {
Live,
Quiesced,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct Link {
pub carrier_refusals: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub carried_by: Option<String>,
pub id: String,
pub name: String,
pub kind: LinkKind,
pub state: LinkState,
#[serde(skip_serializing_if = "Option::is_none")]
pub carrier: Option<Carrier>,
#[serde(skip_serializing_if = "Option::is_none")]
pub relayed: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub crossed: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub refused: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub already_crossed: Option<u64>,
#[serde(flatten)]
pub lifecycle: Option<crate::link::LinkLifeCounters>,
pub rtt_ms: Option<u64>,
pub ends: [String; 2],
}
impl Link {
#[must_use]
pub fn to_peer(local: &str, peer: &str) -> Self {
let ends = if peer < local {
[peer.to_owned(), local.to_owned()]
} else {
[local.to_owned(), peer.to_owned()]
};
Self {
id: format!("{local}~{peer}"),
name: peer.to_owned(),
kind: LinkKind::SameNetwork,
state: LinkState::Up,
rtt_ms: None,
carrier: None,
carrier_refusals: Vec::new(),
carried_by: None,
relayed: None,
reason: None,
crossed: None,
refused: None,
already_crossed: None,
lifecycle: None,
ends,
}
}
#[must_use]
pub fn federated(
local: &str,
peer: &str,
carrier: Option<Carrier>,
state: LinkState,
reason: Option<String>,
counters: LinkCounters,
) -> Self {
let relayed = match &carrier {
Some(Carrier::Relay(device)) => Some(device.clone()),
_ => None,
};
Self {
kind: LinkKind::Federated,
state,
carrier,
carried_by: relayed.clone(),
carrier_refusals: reason.clone().into_iter().collect(),
relayed,
reason: if state == LinkState::Down {
reason
} else {
None
},
crossed: counters.crossed,
refused: counters.refused,
already_crossed: counters.already_crossed,
lifecycle: counters.lifecycle,
..Self::to_peer(local, peer)
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Carrier {
Wire,
Direct,
Relay(String),
}
impl Serialize for Carrier {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(match self {
Self::Wire => "wire",
Self::Direct => "direct",
Self::Relay(_) => "relay",
})
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct LinkCounters {
pub already_crossed: Option<u64>,
pub lifecycle: Option<crate::link::LinkLifeCounters>,
pub crossed: Option<u64>,
pub refused: Option<u64>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
pub enum LinkKind {
#[serde(rename = "same network")]
SameNetwork,
#[serde(rename = "federated")]
Federated,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum LinkState {
Up,
Down,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct Connection {
pub id: String,
pub mount: Mount,
#[serde(skip_serializing_if = "Option::is_none")]
pub participant: Option<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum Mount {
Tcp,
Websocket,
Loopback,
}
impl From<crate::server::mount::MountKind> for Mount {
fn from(mount: crate::server::mount::MountKind) -> Self {
match mount {
crate::server::mount::MountKind::Tcp => Self::Tcp,
crate::server::mount::MountKind::WebSocket => Self::Websocket,
crate::server::mount::MountKind::Loopback => Self::Loopback,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct TopologyDocument {
v: u64,
#[serde(rename = "type")]
record_type: &'static str,
pub rev: u64,
pub this_device: String,
pub devices: Vec<Device>,
pub stations: Vec<Station>,
pub lines: Vec<Line>,
pub links: Vec<Link>,
pub connections: Vec<Connection>,
}
impl TopologyDocument {
#[must_use]
pub const fn new(
rev: u64,
this_device: String,
devices: Vec<Device>,
stations: Vec<Station>,
lines: Vec<Line>,
peer_links: Vec<Link>,
connections: Vec<Connection>,
) -> Self {
Self {
v: RECORD_VERSION,
record_type: "topology",
rev,
this_device,
devices,
stations,
lines,
links: peer_links,
connections,
}
}
}
mod tap_records;
pub use tap_records::{Hop, Outcome, TapBatch, TapMessage, tap_batch_record};
pub const WORKER_REFUSAL_OUTCOME: Outcome = Outcome::Refused;
pub fn canonical_bytes<Record: Serialize>(
record: &Record,
kind: &'static str,
) -> Result<Vec<u8>, ConsoleError> {
serde_json::to_value(record)
.and_then(|value| serde_json::to_vec(&value))
.map_err(|source| ConsoleError::Encode {
record: kind,
source,
})
}