liminal-server 0.25.4

Standalone server for the liminal messaging bus
Documentation
//! One configured chooser supplies the bridge's carrier and the device's incoming endpoint.
use super::super::link_udp_endpoint::UdpEndpoint;
use super::{ServerError, refusal};
use crate::config::types::{MachineConfig, OutboundLinkConfig};
use crate::link::LinkHost;
use crate::link_carrier::choice::ChoiceLink;
use crate::link_open::OpenError;
use crate::link_open::network::{Network, NetworkBackend};
use crate::server::ConnectionSupervisor;
use crate::server::connection::LiminalConnectionServices;
use std::sync::Arc;

pub(super) enum ChoiceOutcome {
    Opened(Box<ChoiceLink>),
    Held { grant: String, draft: String },
    Refused { reason: String },
    DialRefused { reason: String },
}
pub(super) struct ConfiguredChooser {
    network: Arc<Network>,
    machine: MachineConfig,
    services: Option<Arc<LiminalConnectionServices>>,
    supervisor: Option<ConnectionSupervisor>,
    endpoint: Option<UdpEndpoint>,
}
impl ConfiguredChooser {
    pub(super) fn new(host: &Arc<LinkHost>, machine: &MachineConfig) -> Self {
        Self {
            network: Network::new(
                host.clone(),
                machine.clone(),
                machine.carrier_choice.clone(),
            ),
            machine: machine.clone(),
            services: None,
            supervisor: None,
            endpoint: None,
        }
    }
    pub(super) fn with_topology(mut self, services: Arc<LiminalConnectionServices>) -> Self {
        self.services = Some(services);
        self
    }
    pub(super) fn with_endpoint(
        mut self,
        supervisor: &ConnectionSupervisor,
    ) -> Result<Self, ServerError> {
        self.supervisor = Some(supervisor.clone());
        if self.machine.links.is_empty() {
            self.serve_incoming().map_err(|error| refusal(error.0))?;
        }
        Ok(self)
    }
    fn serve_incoming(&mut self) -> Result<(), OpenError> {
        let choice = &self.machine.carrier_choice;
        if self.endpoint.is_some()
            || choice.broker_address.is_none()
            || choice.broker_echo.is_none()
        {
            return Ok(());
        }
        self.endpoint = Some(UdpEndpoint::start(
            self.network.clone(),
            self.supervisor
                .as_ref()
                .ok_or_else(|| OpenError("chooser_has_no_supervisor".to_owned()))?
                .clone(),
            self.services
                .as_ref()
                .ok_or_else(|| OpenError("chooser_has_no_services".to_owned()))?
                .clone(),
        )?);
        Ok(())
    }
    pub(super) fn open(&mut self, entry: &OutboundLinkConfig) -> Result<ChoiceOutcome, OpenError> {
        let services = self
            .services
            .as_ref()
            .ok_or_else(|| OpenError("chooser_has_no_services".to_owned()))?;
        let backend = NetworkBackend::new(self.network.clone(), services.clone(), entry)?;
        match crate::link_open::open(entry.clone(), self.machine.carrier_choice.clone(), backend) {
            Ok(link) => {
                if link.carrier() == Some(crate::link_carrier::Carrier::Direct) {
                    self.serve_incoming()?;
                }
                Ok(ChoiceOutcome::Opened(Box::new(ChoiceLink::chosen(link)?)))
            }
            Err(error) if error.0.starts_with("link_held:") => {
                let (grant, draft) = error
                    .0
                    .strip_prefix("link_held:")
                    .and_then(|held| held.split_once(':'))
                    .ok_or_else(|| OpenError("invalid_held_link_answer".to_owned()))?;
                Ok(ChoiceOutcome::Held {
                    grant: grant.to_owned(),
                    draft: draft.to_owned(),
                })
            }
            Err(error) if error.0.starts_with("link_refused:") => {
                Ok(ChoiceOutcome::Refused { reason: error.0 })
            }
            Err(error) if error.0.starts_with("all_link_carriers_refused:") => {
                Ok(ChoiceOutcome::DialRefused { reason: error.0 })
            }
            Err(error) => Err(error),
        }
    }
    pub(super) fn stop_handle(&self) -> crate::link_open::Stop {
        self.network.stop_handle()
    }
    pub(super) fn finish(&mut self) -> Result<(), ServerError> {
        self.endpoint.take().map_or(Ok(()), |mut endpoint| {
            endpoint.finish().map_err(|error| refusal(error.0))
        })
    }
}