mod envelope;
pub mod framing;
#[cfg(not(target_arch = "wasm32"))]
mod stdio;
use std::future::Future;
use std::io;
use thiserror::Error;
#[cfg(not(target_arch = "wasm32"))]
use crate::builder::Server;
use crate::raw::RawMessage;
#[cfg(not(target_arch = "wasm32"))]
pub use stdio::{StdioReader, StdioTransport, StdioWriter};
#[derive(Debug, Error)]
pub enum TransportError {
#[error("io error: {0}")]
Io(#[from] io::Error),
#[error("connection closed by peer")]
Closed,
#[error("malformed message: {0}")]
Malformed(String),
#[error("message exceeds size limit ({length} > {limit} bytes)")]
OversizedMessage { length: usize, limit: usize },
#[error("serialization error: {0}")]
Serde(#[from] serde_json::Error),
}
pub trait Transport: Send + 'static {
type Reader: TransportReader;
type Writer: TransportWriter;
fn split(self) -> (Self::Reader, Self::Writer);
}
pub trait TransportReader: Send + 'static {
fn recv(
&mut self,
) -> impl Future<Output = std::result::Result<RawMessage, TransportError>> + Send;
}
pub trait TransportWriter: Send + 'static {
fn send(
&mut self,
msg: RawMessage,
) -> impl Future<Output = std::result::Result<(), TransportError>> + Send;
fn shutdown(self) -> impl Future<Output = std::result::Result<(), TransportError>> + Send;
}
#[cfg(not(target_arch = "wasm32"))]
pub fn stdio<S>(server: Server<S>) -> StdioBuilder<S>
where
S: Send + Sync + 'static,
{
StdioBuilder { server }
}
#[cfg(not(target_arch = "wasm32"))]
pub struct StdioBuilder<S> {
server: Server<S>,
}
#[cfg(not(target_arch = "wasm32"))]
impl<S> StdioBuilder<S>
where
S: Send + Sync + 'static,
{
pub async fn serve(self) -> crate::Result<crate::Outcome> {
self.server.serve(StdioTransport::new()).await
}
}
#[cfg(test)]
mod tests {
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use bytes::Bytes;
use super::{
RawMessage, Transport, TransportError, TransportReader, TransportWriter, envelope,
};
use crate::{Outcome, RequestId, Server};
struct FrameTransport {
frames: VecDeque<Bytes>,
outbox: Arc<Mutex<Vec<RawMessage>>>,
}
struct FrameReader {
frames: VecDeque<Bytes>,
}
struct FrameWriter {
outbox: Arc<Mutex<Vec<RawMessage>>>,
}
impl Transport for FrameTransport {
type Reader = FrameReader;
type Writer = FrameWriter;
fn split(self) -> (Self::Reader, Self::Writer) {
(
FrameReader {
frames: self.frames,
},
FrameWriter {
outbox: self.outbox,
},
)
}
}
impl TransportReader for FrameReader {
async fn recv(&mut self) -> Result<RawMessage, TransportError> {
self.frames
.pop_front()
.map(envelope::parse)
.ok_or(TransportError::Closed)
}
}
impl TransportWriter for FrameWriter {
async fn send(&mut self, msg: RawMessage) -> Result<(), TransportError> {
self.outbox.lock().unwrap().push(msg);
Ok(())
}
async fn shutdown(self) -> Result<(), TransportError> {
Ok(())
}
}
struct TestState;
#[tokio::test]
async fn complete_protocol_error_frames_do_not_close_the_connection() {
let outbox = Arc::new(Mutex::new(Vec::new()));
let transport = FrameTransport {
frames: VecDeque::from([
Bytes::from_static(br#"{"jsonrpc":"2.0","method":"initialize""#),
Bytes::from_static(br#"{"jsonrpc":"1.0","method":"initialize"}"#),
Bytes::from_static(
br#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"processId":null,"rootUri":null,"capabilities":{}}}"#,
),
]),
outbox: outbox.clone(),
};
let server = Server::builder(TestState)
.build()
.expect("an empty server builds");
let outcome = server
.serve(transport)
.await
.expect("complete protocol errors do not become transport errors");
assert_eq!(
outcome,
Outcome::TransportClosed,
"the frames run out, so the connection ends on reader EOF"
);
let outbox = outbox.lock().unwrap();
let error_codes: Vec<_> = outbox
.iter()
.filter_map(|message| match message {
RawMessage::ProtocolError { error } => Some(error.code),
_ => None,
})
.collect();
assert_eq!(error_codes, vec![-32700, -32600]);
assert!(
outbox.iter().any(|message| {
matches!(message, RawMessage::Response { id, result: Ok(_) } if *id == RequestId::Number(1))
}),
"initialize after protocol errors should still be processed, got outbox {outbox:#?}"
);
}
}