1use super::framing::{self, FrameError, INVALID_REQUEST, Incoming, PARSE_ERROR};
4use super::notifications::{self, Batch};
5use super::server::Server;
6use super::subscriptions::{Pending, Service};
7use super::writer::Writer;
8use crate::network::Rail;
9use serde_json::Value;
10use std::io::{self, BufRead, Write};
11use std::sync::Arc;
12use std::sync::atomic::Ordering;
13use std::thread::ScopedJoinHandle;
14
15type ReaderThread<'scope> = (Arc<Service>, ScopedJoinHandle<'scope, io::Result<()>>);
16
17impl<R: Rail> Server<R> {
18 pub fn serve<I: BufRead, O: Write + Send>(
24 &mut self,
25 input: &mut I,
26 output: &mut O,
27 ) -> io::Result<()> {
28 if let Err(error) = self.start_listens() {
29 return combine(
30 Err(error),
31 self.channel_source
32 .as_ref()
33 .map_or(Ok(()), |source| source.revoke().map_err(io::Error::other)),
34 );
35 }
36 let writer = Arc::new(Writer::new(
37 output,
38 self.frame_bytes,
39 super::writer::Answers {
40 bytes: self.answer_bytes,
41 dir: self.answer_dir.clone(),
42 },
43 Arc::clone(&self.warning_only),
44 Arc::clone(&self.subscriptions),
45 Arc::clone(&self.listens),
46 ));
47 let served = std::thread::scope(|scope| {
48 let mut readers = Vec::new();
49 let mut channels = Vec::new();
50 let served = self.requests(scope, input, &writer, &mut readers, &mut channels);
51 let mut result = combine(
52 served,
53 self.subscriptions.close_all().map_err(io::Error::other),
54 );
55 result = combine(result, self.listens.close_all().map_err(io::Error::other));
56 for (_, reader) in readers {
57 result = combine(result, joined(reader));
58 }
59 for (_, reader) in channels {
60 result = combine(result, super::channel_serve::joined(reader, &self.listens));
61 }
62 combine(result, writer.check())
63 });
64 combine(
65 served,
66 self.channel_source
67 .as_ref()
68 .map_or(Ok(()), |source| source.revoke().map_err(io::Error::other)),
69 )
70 }
71
72 fn requests<'scope, 'env, I: BufRead, O: Write + Send + 'scope>(
73 &mut self,
74 scope: &'scope std::thread::Scope<'scope, 'env>,
75 input: &mut I,
76 writer: &Arc<Writer<O>>,
77 readers: &mut Vec<ReaderThread<'scope>>,
78 channels: &mut Vec<super::channel_serve::Reader<'scope>>,
79 ) -> io::Result<()> {
80 let context = super::channel_serve::Context {
81 config: self.listen_config.clone(),
82 device: self.rail().server_address().to_owned(),
83 record_bytes: self
84 .channel_source
85 .as_ref()
86 .map_or(self.frame_bytes, |source| source.record_bytes),
87 };
88 super::channel_serve::spawn(scope, channels, &self.listens, writer, &context)?;
89 loop {
90 writer.check()?;
91 join_closed(readers)?;
92 super::channel_serve::join_closed(channels, &self.listens)?;
93 let incoming = framing::read_message(input, self.frame_bytes);
94 writer.check()?;
95 let answer = match incoming {
96 Ok(None) => return Ok(()),
97 Ok(Some(Incoming::Notification { .. })) => continue,
98 Ok(Some(Incoming::Request { id, method, params })) => {
99 self.answer(&id, &method, ¶ms)
100 }
101 Err(FrameError::Stream { message }) => return Err(io::Error::other(message)),
102 Err(error @ (FrameError::Overlong { .. } | FrameError::NotRequest { .. })) => {
103 framing::error(&Value::Null, INVALID_REQUEST, &error.to_string(), None)
104 }
105 Err(error @ FrameError::NotJson { .. }) => {
106 framing::error(&Value::Null, PARSE_ERROR, &error.to_string(), None)
107 }
108 };
109 join_closed(readers)?;
110 super::channel_serve::join_closed(channels, &self.listens)?;
111 writer.write(answer, None, false)?;
112 spawn_taps(
113 scope,
114 self.subscriptions.pending().map_err(io::Error::other)?,
115 writer,
116 readers,
117 )?;
118 super::channel_serve::spawn(scope, channels, &self.listens, writer, &context)?;
119 }
120 }
121}
122
123fn joined(reader: ScopedJoinHandle<'_, io::Result<()>>) -> io::Result<()> {
124 reader
125 .join()
126 .map_err(|_| io::Error::other("a tap receiver thread panicked"))?
127}
128
129fn spawn_taps<'scope, 'env, O: Write + Send + 'scope>(
130 scope: &'scope std::thread::Scope<'scope, 'env>,
131 pending: Vec<Pending>,
132 writer: &Arc<Writer<O>>,
133 readers: &mut Vec<ReaderThread<'scope>>,
134) -> io::Result<()> {
135 for pending in pending {
136 let writer = Arc::clone(writer);
137 let service = Arc::clone(&pending.service);
138 let reader = std::thread::Builder::new()
139 .name("liminal-mcp-tap".to_owned())
140 .spawn_scoped(scope, move || receive(&pending, &writer))?;
141 readers.push((service, reader));
142 }
143 Ok(())
144}
145
146fn join_closed(readers: &mut Vec<ReaderThread<'_>>) -> io::Result<()> {
147 let mut n = 0;
148 while n < readers.len() {
149 if readers[n].0.active.load(Ordering::SeqCst) {
150 n += 1;
151 } else {
152 joined(readers.swap_remove(n).1)?;
153 }
154 }
155 Ok(())
156}
157
158fn combine(first: io::Result<()>, second: io::Result<()>) -> io::Result<()> {
159 match (first, second) {
160 (Ok(()), result) | (result, Ok(())) => result,
161 (Err(first), Err(second)) => Err(io::Error::other(format!("{first}; {second}"))),
162 }
163}
164
165fn receive<O: Write>(pending: &Pending, writer: &Writer<O>) -> io::Result<()> {
166 while pending.service.active.load(Ordering::SeqCst) {
167 let batch = pending
168 .reader
169 .receive()
170 .map_err(|error| error.to_string())
171 .and_then(|record| Batch::read(record, &pending.subject));
172 let batch = match batch {
173 Ok(batch) => batch,
174 Err(reason) => {
175 if pending.service.active.swap(false, Ordering::SeqCst) {
176 let closed = pending.service.close();
177 let reason = match closed {
178 Ok(()) => reason,
179 Err(words) => format!("{reason}; subscription teardown failed: {words}"),
180 };
181 return writer.write(
182 notifications::warning(
183 &pending.service,
184 &pending.subject,
185 "ended",
186 &format!("subscription to {} ended: {reason}", pending.service.name),
187 ),
188 Some(&pending.service),
189 true,
190 );
191 }
192 return Ok(());
193 }
194 };
195 writer.record(&pending.service, &pending.subject, &batch)?;
196 }
197 Ok(())
198}