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 failure: std::sync::OnceLock::new(),
48 },
49 })
50 }
51}
52impl From<DialedLink> for ChoiceLink {
53 fn from(link: DialedLink) -> Self {
54 let life = link.carrier.life().cloned();
55 Self {
56 link_id: link.link_id,
57 exports: link.exports,
58 transport: Preparation::Wire(link.transport),
59 carrier: ChoiceCarrier {
60 path: Path::Wire(link.carrier),
61 last: Carrier::Wire,
62 life,
63 observed: Arc::new(Mutex::new(Some(ObservedCarrier::Wire))),
64 interrupt: None,
65 answer: None,
66 failure: std::sync::OnceLock::new(),
67 },
68 }
69 }
70}
71#[derive(Debug)]
72pub(crate) enum Preparation {
73 Wire(LinkTransport),
74 Chosen(MachineIdentity),
75}
76impl Preparation {
77 pub(crate) const fn peer(&self) -> &MachineIdentity {
78 match self {
79 Self::Wire(transport) => transport.peer(),
80 Self::Chosen(peer) => peer,
81 }
82 }
83 pub(crate) fn prepare(&mut self, plain: &[u8], output: &mut [u8]) -> Result<usize, OpenError> {
84 match self {
85 Self::Wire(transport) => transport
86 .seal(plain, output)
87 .map_err(|error| OpenError(error.to_string())),
88 Self::Chosen(_) => {
89 let target = output
90 .get_mut(..plain.len())
91 .ok_or_else(|| OpenError("crossing_buffer_too_small".to_owned()))?;
92 target.copy_from_slice(plain);
93 Ok(plain.len())
94 }
95 }
96 }
97}
98#[derive(Debug)]
99enum Path {
100 Wire(WireCarrier),
101 Chosen(Box<Opened<NetworkBackend>>),
102}
103#[derive(Debug)]
104pub(crate) struct ChoiceCarrier {
105 path: Path,
106 last: Carrier,
107 life: Option<LinkLife>,
108 observed: Arc<Mutex<Option<ObservedCarrier>>>,
109 interrupt: Option<Interrupt>,
110 answer: Option<CarrierReceive>,
111 failure: std::sync::OnceLock<String>,
113}
114impl ChoiceCarrier {
115 pub(crate) fn interrupt_handle(&mut self) -> Result<Interrupt, CarrierError> {
116 match &self.path {
117 Path::Wire(wire) => wire.interrupt_handle().map(Interrupt::wire),
118 Path::Chosen(_) => self.interrupt.take().ok_or(CarrierError::Ended),
119 }
120 }
121 pub(crate) const fn life(&self) -> Option<&LinkLife> {
122 self.life.as_ref()
123 }
124 pub(crate) fn observe_carrier(&self) -> Arc<Mutex<Option<ObservedCarrier>>> {
125 Arc::clone(&self.observed)
126 }
127 pub(crate) fn refuse_unsolicited(&self) -> Result<(), CarrierError> {
128 match &self.path {
129 Path::Wire(wire) => wire.refuse_unsolicited(),
130 Path::Chosen(link) => link
131 .refuse_unsolicited()
132 .map_err(|error| CarrierError::Lifecycle(error.0)),
133 }
134 }
135}
136impl LinkCarrier for ChoiceCarrier {
137 fn carrier(&self) -> Carrier {
138 self.last
139 }
140 fn ended(&self) -> Option<String> {
141 match &self.path {
142 Path::Wire(wire) => wire.ended(),
143 Path::Chosen(_) => self.failure.get().cloned().or_else(|| {
144 self.life
145 .as_ref()
146 .and_then(|life| life.reason().ok().flatten())
147 }),
148 }
149 }
150 fn send(&mut self, subject: &str, sealed: &[u8]) -> Result<(), CarrierError> {
151 match &mut self.path {
152 Path::Wire(wire) => wire.send(subject, sealed),
153 Path::Chosen(link) => {
154 let result = link.send(subject, sealed);
155 if let Some(carrier) = link.carrier() {
156 self.last = carrier;
157 }
158 *self.observed.lock().map_err(|_| {
159 CarrierError::Lifecycle("carrier_observation_poisoned".to_owned())
160 })? = link.observed_carrier();
161 match result {
162 Ok(()) => {
163 let message_id = u64::from_be_bytes(
164 sealed
165 .get(..8)
166 .ok_or(CarrierError::UnexpectedFrame)?
167 .try_into()
168 .map_err(|_| CarrierError::UnexpectedFrame)?,
169 );
170 self.answer = Some(CarrierReceive::Acknowledged {
171 message_id,
172 durable_position: None,
173 });
174 Ok(())
175 }
176 Err(error) if error.0.starts_with("crossing_refused:") => {
177 let parts = error
178 .0
179 .strip_prefix("crossing_refused:")
180 .and_then(|value| value.split_once(':'))
181 .ok_or(CarrierError::UnexpectedFrame)?;
182 self.answer = Some(CarrierReceive::Refused {
183 reason_code: parts
184 .0
185 .parse()
186 .map_err(|_| CarrierError::UnexpectedFrame)?,
187 reason: Some(parts.1.to_owned()),
188 });
189 Ok(())
190 }
191 Err(error)
192 if link.stopped()
193 || matches!(
194 error.0.as_str(),
195 "network_stopped" | "udp_receiver_stopped"
196 ) =>
197 {
198 self.failure.get_or_init(|| error.0.clone());
199 Err(std::io::Error::new(std::io::ErrorKind::Interrupted, error.0).into())
200 }
201 Err(error) => {
202 self.failure.get_or_init(|| error.0.clone());
203 if let Some(life) = &self.life {
204 life.end(LinkEnd::Refused(error.0.clone()))
205 .map_err(CarrierError::Lifecycle)?;
206 }
207 Err(CarrierError::Lifecycle(error.0))
208 }
209 }
210 }
211 }
212 }
213 fn receive(&mut self) -> Result<CarrierReceive, CarrierError> {
214 match &mut self.path {
215 Path::Wire(wire) => wire.receive(),
216 Path::Chosen(_) => self.answer.take().ok_or(CarrierError::UnexpectedFrame),
217 }
218 }
219}