liminal_server/link_carrier/
choice.rs1use super::{Carrier, CarrierError, CarrierReceive, LinkCarrier, WireCarrier};
3use crate::console::records::Carrier as ObservedCarrier;
4use crate::link::{LinkEnd, LinkLife};
5use crate::link_dial::DialedLink;
6use crate::link_handshake::{LinkTransport, MachineIdentity};
7use crate::link_open::network::NetworkBackend;
8use crate::link_open::{OpenError, Opened};
9use std::sync::{Arc, Mutex};
10mod stop;
11pub use stop::Interrupt;
12
13#[derive(Debug)]
15pub struct ChoiceLink {
16 pub(crate) link_id: String,
17 pub(crate) exports: Vec<String>,
18 pub(crate) transport: Preparation,
19 pub(crate) carrier: ChoiceCarrier,
20}
21impl ChoiceLink {
22 pub fn chosen(link: Opened<NetworkBackend>) -> Result<Self, OpenError> {
26 let peer = link.backend().peer();
27 let link_id = link.description().link_id.clone();
28 let exports = link.description().exports.clone();
29 let stop = link.interrupt_handle()?;
30 let interrupt = Interrupt::chosen(stop.clone())?;
31 let last = link
32 .carrier()
33 .ok_or_else(|| OpenError("link_has_no_carrier".to_owned()))?;
34 let life = link.life().unwrap_or_else(|| LinkLife::new(peer));
35 let observed = Arc::new(Mutex::new(link.observed_carrier()));
36 Ok(Self {
37 link_id,
38 exports,
39 transport: Preparation::Chosen(peer),
40 carrier: ChoiceCarrier {
41 path: Path::Chosen(Box::new(link)),
42 last,
43 life: Some(life),
44 observed,
45 interrupt: Some(interrupt),
46 answer: None,
47 },
48 })
49 }
50}
51impl From<DialedLink> for ChoiceLink {
52 fn from(link: DialedLink) -> Self {
53 let life = link.carrier.life().cloned();
54 Self {
55 link_id: link.link_id,
56 exports: link.exports,
57 transport: Preparation::Wire(link.transport),
58 carrier: ChoiceCarrier {
59 path: Path::Wire(link.carrier),
60 last: Carrier::Wire,
61 life,
62 observed: Arc::new(Mutex::new(Some(ObservedCarrier::Wire))),
63 interrupt: None,
64 answer: None,
65 },
66 }
67 }
68}
69#[derive(Debug)]
70pub(crate) enum Preparation {
71 Wire(LinkTransport),
72 Chosen(MachineIdentity),
73}
74impl Preparation {
75 pub(crate) const fn peer(&self) -> &MachineIdentity {
76 match self {
77 Self::Wire(transport) => transport.peer(),
78 Self::Chosen(peer) => peer,
79 }
80 }
81 pub(crate) fn prepare(&mut self, plain: &[u8], output: &mut [u8]) -> Result<usize, OpenError> {
82 match self {
83 Self::Wire(transport) => transport
84 .seal(plain, output)
85 .map_err(|error| OpenError(error.to_string())),
86 Self::Chosen(_) => {
87 let target = output
88 .get_mut(..plain.len())
89 .ok_or_else(|| OpenError("crossing_buffer_too_small".to_owned()))?;
90 target.copy_from_slice(plain);
91 Ok(plain.len())
92 }
93 }
94 }
95}
96#[derive(Debug)]
97enum Path {
98 Wire(WireCarrier),
99 Chosen(Box<Opened<NetworkBackend>>),
100}
101#[derive(Debug)]
102pub(crate) struct ChoiceCarrier {
103 path: Path,
104 last: Carrier,
105 life: Option<LinkLife>,
106 observed: Arc<Mutex<Option<ObservedCarrier>>>,
107 interrupt: Option<Interrupt>,
108 answer: Option<CarrierReceive>,
109}
110impl ChoiceCarrier {
111 pub(crate) fn interrupt_handle(&mut self) -> Result<Interrupt, CarrierError> {
112 match &self.path {
113 Path::Wire(wire) => wire.interrupt_handle().map(Interrupt::wire),
114 Path::Chosen(_) => self.interrupt.take().ok_or(CarrierError::Ended),
115 }
116 }
117 pub(crate) const fn life(&self) -> Option<&LinkLife> {
118 self.life.as_ref()
119 }
120 pub(crate) fn observe_carrier(&self) -> Arc<Mutex<Option<ObservedCarrier>>> {
121 Arc::clone(&self.observed)
122 }
123 pub(crate) fn refuse_unsolicited(&self) -> Result<(), CarrierError> {
124 match &self.path {
125 Path::Wire(wire) => wire.refuse_unsolicited(),
126 Path::Chosen(link) => link
127 .refuse_unsolicited()
128 .map_err(|error| CarrierError::Lifecycle(error.0)),
129 }
130 }
131}
132impl LinkCarrier for ChoiceCarrier {
133 fn carrier(&self) -> Carrier {
134 self.last
135 }
136 fn send(&mut self, subject: &str, sealed: &[u8]) -> Result<(), CarrierError> {
137 match &mut self.path {
138 Path::Wire(wire) => wire.send(subject, sealed),
139 Path::Chosen(link) => {
140 let result = link.send(subject, sealed);
141 if let Some(carrier) = link.carrier() {
142 self.last = carrier;
143 }
144 *self.observed.lock().map_err(|_| {
145 CarrierError::Lifecycle("carrier_observation_poisoned".to_owned())
146 })? = link.observed_carrier();
147 match result {
148 Ok(()) => {
149 let message_id = u64::from_be_bytes(
150 sealed
151 .get(..8)
152 .ok_or(CarrierError::UnexpectedFrame)?
153 .try_into()
154 .map_err(|_| CarrierError::UnexpectedFrame)?,
155 );
156 self.answer = Some(CarrierReceive::Acknowledged {
157 message_id,
158 durable_position: None,
159 });
160 Ok(())
161 }
162 Err(error) if error.0.starts_with("crossing_refused:") => {
163 let parts = error
164 .0
165 .strip_prefix("crossing_refused:")
166 .and_then(|value| value.split_once(':'))
167 .ok_or(CarrierError::UnexpectedFrame)?;
168 self.answer = Some(CarrierReceive::Refused {
169 reason_code: parts
170 .0
171 .parse()
172 .map_err(|_| CarrierError::UnexpectedFrame)?,
173 reason: Some(parts.1.to_owned()),
174 });
175 Ok(())
176 }
177 Err(error)
178 if link.stopped()
179 || matches!(
180 error.0.as_str(),
181 "network_stopped" | "udp_receiver_stopped"
182 ) =>
183 {
184 Err(std::io::Error::new(std::io::ErrorKind::Interrupted, error.0).into())
185 }
186 Err(error) => {
187 if let Some(life) = &self.life {
188 life.end(LinkEnd::Refused(error.0.clone()))
189 .map_err(CarrierError::Lifecycle)?;
190 }
191 Err(CarrierError::Lifecycle(error.0))
192 }
193 }
194 }
195 }
196 }
197 fn receive(&mut self) -> Result<CarrierReceive, CarrierError> {
198 match &mut self.path {
199 Path::Wire(wire) => wire.receive(),
200 Path::Chosen(_) => self.answer.take().ok_or(CarrierError::UnexpectedFrame),
201 }
202 }
203}