hatchery_server/
drain_consumer.rs1use hatchery_c2_client::{DrainClient, DrainSession};
11use hatchery_core::inner::{decode_inner, encode_inner, InnerKind};
12use hatchery_core::nested::{HqRecipientSecret, NoiseResponder, NoiseTransport};
13use hatchery_core::ChannelKind;
14use std::sync::Arc;
15use std::time::Duration;
16use tokio::sync::watch;
17
18pub type CoreHandler = Arc<dyn Fn(&str, ChannelKind, &[u8]) -> Option<Vec<u8>> + Send + Sync>;
21
22pub struct NodeStream {
23 pub node_id: String,
24 pub channel_id: u32,
25 pub kind: ChannelKind,
26}
27
28pub struct DrainConsumer {
29 client: DrainClient,
30 recipient: HqRecipientSecret,
31 stream: NodeStream,
32 handler: CoreHandler,
33 last_acked: u64,
34 transport: Option<NoiseTransport>,
35 outbound: Option<tokio::sync::mpsc::Receiver<Vec<u8>>>,
37}
38
39impl DrainConsumer {
40 pub fn new(client: DrainClient, recipient: HqRecipientSecret, stream: NodeStream, handler: CoreHandler) -> Self {
41 Self { client, recipient, stream, handler, last_acked: 0, transport: None, outbound: None }
42 }
43
44 pub fn with_outbound(mut self, rx: tokio::sync::mpsc::Receiver<Vec<u8>>) -> Self {
46 self.outbound = Some(rx);
47 self
48 }
49
50 pub fn last_acked(&self) -> u64 {
51 self.last_acked
52 }
53
54 pub async fn run(mut self, mut shutdown: watch::Receiver<bool>) {
56 let mut backoff = Duration::from_millis(50);
57 while !*shutdown.borrow() {
58 match self.session(&mut shutdown).await {
59 Ok(()) => backoff = Duration::from_millis(50),
60 Err(err) => tracing::debug!(error = %err, "drain session ended"),
61 }
62 if *shutdown.borrow() {
63 break;
64 }
65 tokio::select! {
66 _ = tokio::time::sleep(backoff) => {}
67 _ = shutdown.changed() => {}
68 }
69 backoff = (backoff * 2).min(Duration::from_secs(5));
70 }
71 }
72
73 async fn session(&mut self, shutdown: &mut watch::Receiver<bool>) -> Result<(), String> {
74 self.transport = None;
76 let mut s = self.client.connect().await.map_err(|e| e.to_string())?;
77 s.open(&self.stream.node_id, self.stream.channel_id, self.stream.kind).await.map_err(|e| e.to_string())?;
78 s.resume(self.last_acked).await.map_err(|e| e.to_string())?;
79 loop {
80 if *shutdown.borrow() {
81 return Ok(());
82 }
83 let ready = self.transport.is_some();
84 let env = tokio::select! {
85 env = s.recv_envelope(Duration::from_millis(250)) => env.map_err(|e| e.to_string())?,
86 Some(plain) = async {
87 match self.outbound.as_mut() {
88 Some(rx) if ready => rx.recv().await,
89 _ => std::future::pending().await,
90 }
91 } => {
92 let ct = self.transport.as_mut().expect("transport").encrypt(&plain).map_err(|e| e.to_string())?;
93 s.send_data(self.stream.channel_id, encode_inner(InnerKind::Transport, &ct))
94 .await
95 .map_err(|e| e.to_string())?;
96 continue;
97 }
98 _ = shutdown.changed() => return Ok(()),
99 };
100 let Some(env) = env else { continue };
101 if env.node_id != self.stream.node_id {
102 continue;
103 }
104 let seq = env.frame.seq;
105 if seq != 0 && seq <= self.last_acked {
106 continue;
107 }
108 self.handle(&mut s, &env.frame.payload).await?;
109 if seq != 0 {
110 s.ack(seq).await.map_err(|e| e.to_string())?;
111 self.last_acked = seq;
112 }
113 }
114 }
115
116 async fn handle(&mut self, s: &mut DrainSession, inner: &[u8]) -> Result<(), String> {
117 match decode_inner(inner) {
118 Some((InnerKind::Handshake1, msg1)) => {
119 let responder = NoiseResponder::new(&self.recipient).map_err(|e| e.to_string())?;
120 match responder.complete(msg1) {
121 Ok((msg2, transport)) => {
122 self.transport = Some(transport);
123 s.send_data(self.stream.channel_id, encode_inner(InnerKind::Handshake2, &msg2))
124 .await
125 .map_err(|e| e.to_string())?;
126 }
127 Err(err) => tracing::debug!(error = %err, "handshake refused"),
129 }
130 }
131 Some((InnerKind::Transport, ct)) => {
132 let Some(transport) = self.transport.as_mut() else { return Ok(()) };
133 let Ok(plain) = transport.decrypt(ct) else {
134 tracing::warn!(node = %self.stream.node_id, channel = self.stream.channel_id, "inner decrypt failed; resetting Noise session");
137 self.transport = None;
138 return Ok(());
139 };
140 let handler = Arc::clone(&self.handler);
141 let node = self.stream.node_id.clone();
142 let kind = self.stream.kind;
143 let reply = tokio::task::spawn_blocking(move || handler(&node, kind, &plain))
144 .await
145 .map_err(|e| e.to_string())?;
146 if let Some(reply) = reply {
147 let ct = self.transport.as_mut().expect("transport").encrypt(&reply).map_err(|e| e.to_string())?;
148 s.send_data(self.stream.channel_id, encode_inner(InnerKind::Transport, &ct))
149 .await
150 .map_err(|e| e.to_string())?;
151 }
152 }
153 _ => {}
154 }
155 Ok(())
156 }
157}