use super::{Backend, Deadline, Facts, OpenError, Packet, Path};
use liminal_server::config::types::{MachineConfig, OutboundLinkConfig};
use liminal_server::link::LinkHost;
use liminal_server::link_carrier::{Carrier, CarrierReceive, LinkCarrier};
use liminal_server::link_dial::{DialedLink, LinkDialOutcome, LinkDialer};
use liminal_server::link_handshake::NOISE_OVERHEAD;
use std::sync::{Arc, Mutex};
pub use crate::support::federation;
fn named(error: impl std::fmt::Display) -> OpenError {
OpenError(error.to_string())
}
#[derive(Debug)]
pub struct WireBackend {
host: Arc<LinkHost>,
machine: MachineConfig,
facts: Arc<Mutex<Facts>>,
}
impl WireBackend {
pub fn new(fixture: &federation::Federation, facts: Arc<Mutex<Facts>>) -> Self {
Self {
host: Arc::clone(&fixture.exporter.host),
machine: fixture.exporter.config.clone(),
facts,
}
}
}
#[derive(Debug)]
struct WirePath(Box<DialedLink>);
impl Path for WirePath {
fn carrier(&self) -> Carrier {
Carrier::Wire
}
fn relay_device(&self) -> Option<String> {
None
}
fn prepare(&mut self, subject: &str, plain: &[u8]) -> Result<Packet, OpenError> {
let counter = self.0.transport.sending_nonce();
let mut bytes = vec![0; plain.len() + NOISE_OVERHEAD];
let length = self.0.transport.seal(plain, &mut bytes).map_err(named)?;
bytes.truncate(length);
Ok(Packet {
subject: subject.to_owned(),
counter,
bytes,
deadline: None,
})
}
fn transmit(&mut self, packet: &Packet) -> Result<(), OpenError> {
self.0
.carrier
.send(&packet.subject, &packet.bytes)
.map_err(named)
}
fn receipt(&mut self, _counter: u64, bound: Option<Deadline>) -> Result<bool, OpenError> {
assert_eq!(bound, None);
match self.0.carrier.receive().map_err(named)? {
CarrierReceive::Acknowledged { .. } => Ok(true),
answer => Err(OpenError(format!("unexpected_wire_answer: {answer:?}"))),
}
}
}
impl Backend for WireBackend {
fn wire(
&mut self,
config: &OutboundLinkConfig,
address: &str,
) -> Result<Box<dyn Path>, OpenError> {
self.facts
.lock()
.map_err(named)?
.calls
.push(address.to_owned());
let mut entry = config.clone();
entry.peer_address = Some(address.to_owned());
match LinkDialer::new(&self.host, &self.machine)
.open(&entry)
.map_err(named)?
{
LinkDialOutcome::Opened(link) => Ok(Box::new(WirePath(link))),
answer => Err(OpenError(format!("wire_open_did_not_key: {answer:?}"))),
}
}
fn lookup(&mut self, _config: &OutboundLinkConfig) -> Result<Vec<String>, OpenError> {
Err(OpenError("unexpected_broker_lookup".to_owned()))
}
fn punch(&mut self, _config: &OutboundLinkConfig) -> Result<Box<dyn Path>, OpenError> {
Err(OpenError("unexpected_punch".to_owned()))
}
fn relay(&mut self, _config: &OutboundLinkConfig) -> Result<Box<dyn Path>, OpenError> {
Err(OpenError("unexpected_relay".to_owned()))
}
fn repunch(
&mut self,
_config: &OutboundLinkConfig,
_path: &mut dyn Path,
) -> Result<(), OpenError> {
Err(OpenError("unexpected_repunch".to_owned()))
}
fn topology(
&mut self,
carrier: Option<Carrier>,
relay: Option<String>,
refusal: Option<&str>,
) -> Result<(), OpenError> {
self.facts.lock().map_err(named)?.topology.push((
carrier,
relay,
refusal.map(str::to_owned),
));
Ok(())
}
}