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