1use std::cell::RefCell;
23use std::rc::Rc;
24
25use confium_core::Confium;
26use serde_json::Value;
27use tokio::io::{AsyncReadExt, AsyncWriteExt};
28use tokio::net::TcpListener;
29use tokio::task::LocalSet;
30use tokio_util::sync::CancellationToken;
31
32use crate::dispatch::Dispatch;
33use crate::error::{self, DaemonError, RpcError};
34use crate::protocol::{RpcRequest, RpcResponse};
35
36pub type SharedConfium = Rc<RefCell<Confium>>;
39
40pub struct Server {
43 pub cfm: SharedConfium,
46
47 pub dispatch: Dispatch,
49
50 pub cancel: CancellationToken,
53}
54
55impl Server {
56 pub fn new() -> Self {
59 Server {
60 cfm: Rc::new(RefCell::new(Confium::new())),
61 dispatch: Dispatch::new(),
62 cancel: CancellationToken::new(),
63 }
64 }
65
66 pub fn with_confium(cfm: Confium) -> Self {
69 Server {
70 cfm: Rc::new(RefCell::new(cfm)),
71 dispatch: Dispatch::new(),
72 cancel: CancellationToken::new(),
73 }
74 }
75
76 pub async fn serve_tcp(self: Rc<Self>, listener: TcpListener) -> error::Result<()> {
79 let shutdown = self.cancel.clone();
80 loop {
81 tokio::select! {
82 biased;
83 _ = shutdown.cancelled() => break,
84 accept = listener.accept() => {
85 let (stream, _peer) = accept?;
86 let server = Rc::clone(&self);
87 tokio::task::spawn_local(async move {
90 let _ = server.handle_tcp(stream).await;
91 });
92 }
93 }
94 }
95 Ok(())
96 }
97
98 #[cfg(unix)]
100 pub async fn serve_unix(
101 self: Rc<Self>,
102 listener: tokio::net::UnixListener,
103 ) -> error::Result<()> {
104 let shutdown = self.cancel.clone();
105 loop {
106 tokio::select! {
107 biased;
108 _ = shutdown.cancelled() => break,
109 accept = listener.accept() => {
110 let (stream, _peer) = accept?;
111 let server = Rc::clone(&self);
112 tokio::task::spawn_local(async move {
113 let _ = server.handle_unix(stream).await;
114 });
115 }
116 }
117 }
118 Ok(())
119 }
120
121 pub async fn run_tcp(self: Rc<Self>, listener: TcpListener) -> error::Result<()> {
125 let local = LocalSet::new();
126 local.run_until(self.serve_tcp(listener)).await
127 }
128
129 #[cfg(unix)]
131 pub async fn run_unix(self: Rc<Self>, listener: tokio::net::UnixListener) -> error::Result<()> {
132 let local = LocalSet::new();
133 local.run_until(self.serve_unix(listener)).await
134 }
135
136 async fn handle_tcp(self: Rc<Self>, stream: tokio::net::TcpStream) -> error::Result<()> {
140 let (mut read, mut write) = tokio::io::split(stream);
141 Self::drive_connection(&self, &mut read, &mut write).await
142 }
143
144 #[cfg(unix)]
146 async fn handle_unix(self: Rc<Self>, stream: tokio::net::UnixStream) -> error::Result<()> {
147 let (mut read, mut write) = tokio::io::split(stream);
148 Self::drive_connection(&self, &mut read, &mut write).await
149 }
150
151 async fn drive_connection<R, W>(
154 self: &Rc<Self>,
155 read: &mut R,
156 write: &mut W,
157 ) -> error::Result<()>
158 where
159 R: AsyncReadExt + Unpin,
160 W: AsyncWriteExt + Unpin,
161 {
162 loop {
163 let msg = match read_length_prefixed(read).await? {
164 Some(m) => m,
165 None => return Ok(()), };
167 let response = self.process(&msg).await;
168 if let Some(resp) = response {
169 let bytes = serde_json::to_vec(&resp)?;
170 write_length_prefixed(write, &bytes).await?;
171 }
172 if self.cancel.is_cancelled() {
173 break;
174 }
175 }
176 Ok(())
177 }
178
179 async fn process(self: &Rc<Self>, raw: &[u8]) -> Option<RpcResponse> {
182 let req: RpcRequest = match serde_json::from_slice(raw) {
183 Ok(r) => r,
184 Err(e) => {
185 return Some(RpcResponse::err(
186 Value::Null,
187 RpcError::InvalidParams {
188 detail: format!("parse error: {e}"),
189 },
190 ));
191 }
192 };
193
194 if !req.version_ok() {
195 return Some(RpcResponse::err(
196 req.id.unwrap_or(Value::Null),
197 RpcError::InvalidParams {
198 detail: "jsonrpc must be \"2.0\"".to_string(),
199 },
200 ));
201 }
202
203 let is_shutdown = req.method == "shutdown";
205
206 let handler = match self.dispatch.get(&req.method) {
207 Some(h) => h,
208 None => {
209 return if req.is_notification() {
210 None
211 } else {
212 Some(RpcResponse::err(
213 req.id.unwrap_or(Value::Null),
214 RpcError::MethodNotFound {
215 method: req.method.clone(),
216 },
217 ))
218 };
219 }
220 };
221
222 let result = handler(Rc::clone(&self.cfm), req.params.clone()).await;
223
224 if is_shutdown {
225 self.cancel.cancel();
226 }
227
228 if req.is_notification() {
229 return None;
230 }
231
232 let id = req.id.unwrap_or(Value::Null);
233 Some(match result {
234 Ok(value) => RpcResponse::ok(id, value),
235 Err(err) => RpcResponse::err(id, err),
236 })
237 }
238}
239
240impl Default for Server {
241 fn default() -> Self {
242 Self::new()
243 }
244}
245
246async fn read_length_prefixed<R: AsyncReadExt + Unpin>(
253 reader: &mut R,
254) -> error::Result<Option<Vec<u8>>> {
255 let mut len_buf = [0u8; 4];
256 match reader.read_exact(&mut len_buf).await {
259 Ok(_) => {}
260 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return Ok(None),
261 Err(e) => return Err(DaemonError::Io { source: e }),
262 }
263 let len = u32::from_be_bytes(len_buf) as usize;
264 const MAX_MESSAGE: usize = 16 * 1024 * 1024;
267 if len > MAX_MESSAGE {
268 return Err(DaemonError::Io {
269 source: std::io::Error::new(
270 std::io::ErrorKind::InvalidData,
271 format!("message length {len} exceeds {MAX_MESSAGE}"),
272 ),
273 });
274 }
275 let mut buf = vec![0u8; len];
276 reader.read_exact(&mut buf).await?;
277 Ok(Some(buf))
278}
279
280async fn write_length_prefixed<W: AsyncWriteExt + Unpin>(
282 writer: &mut W,
283 payload: &[u8],
284) -> error::Result<()> {
285 let len = payload.len() as u32;
286 writer.write_all(&len.to_be_bytes()).await?;
287 writer.write_all(payload).await?;
288 writer.flush().await?;
289 Ok(())
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295 use confium_core::audit::AuditLogger;
296
297 fn server() -> Server {
298 Server::with_confium(Confium::new_with_audit(AuditLogger::disabled()))
299 }
300
301 #[tokio::test]
302 async fn process_unknown_method_returns_method_not_found() {
303 let local = LocalSet::new();
304 local
305 .run_until(async {
306 let s = Rc::new(server());
307 let raw = br#"{"jsonrpc":"2.0","id":1,"method":"does_not_exist","params":{}}"#;
308 let resp = s.process(raw).await.unwrap();
309 let serialized = serde_json::to_value(&resp).unwrap();
310 assert_eq!(
311 serialized["error"]["code"],
312 RpcError::MethodNotFound { method: "".into() }.code()
313 );
314 })
315 .await;
316 }
317
318 #[tokio::test]
319 async fn process_version_returns_pkg_version() {
320 let local = LocalSet::new();
321 local
322 .run_until(async {
323 let s = Rc::new(server());
324 let raw = br#"{"jsonrpc":"2.0","id":1,"method":"version","params":{}}"#;
325 let resp = s.process(raw).await.unwrap();
326 let serialized = serde_json::to_value(&resp).unwrap();
327 assert_eq!(serialized["result"]["version"], env!("CARGO_PKG_VERSION"));
328 })
329 .await;
330 }
331
332 #[tokio::test]
333 async fn process_bad_json_returns_parse_error() {
334 let local = LocalSet::new();
335 local
336 .run_until(async {
337 let s = Rc::new(server());
338 let resp = s.process(b"not json").await.unwrap();
339 let serialized = serde_json::to_value(&resp).unwrap();
340 assert!(
341 serialized["error"]["message"]
342 .as_str()
343 .unwrap()
344 .contains("parse error")
345 );
346 })
347 .await;
348 }
349
350 #[tokio::test]
351 async fn process_notification_returns_none() {
352 let local = LocalSet::new();
353 local
354 .run_until(async {
355 let s = Rc::new(server());
356 let raw = br#"{"jsonrpc":"2.0","method":"version","params":{}}"#;
358 let resp = s.process(raw).await;
359 assert!(resp.is_none());
360 })
361 .await;
362 }
363
364 #[tokio::test]
365 async fn shutdown_triggers_cancellation() {
366 let local = LocalSet::new();
367 local
368 .run_until(async {
369 let s = Rc::new(server());
370 let raw = br#"{"jsonrpc":"2.0","id":1,"method":"shutdown","params":{}}"#;
371 let _ = s.process(raw).await;
372 assert!(s.cancel.is_cancelled());
373 })
374 .await;
375 }
376
377 #[tokio::test]
378 async fn length_prefixed_roundtrip() {
379 let payload = br#"{"jsonrpc":"2.0","id":1,"method":"version"}"#;
382 let mut buf = Vec::new();
383 write_length_prefixed(&mut buf, payload).await.unwrap();
384
385 let mut cursor = std::io::Cursor::new(buf);
386 let msg = read_length_prefixed(&mut cursor).await.unwrap().unwrap();
387 assert_eq!(msg, payload);
388 }
389}