use std::error::Error;
use std::fmt::Debug;
use std::io::{self, BufRead, BufReader, Read};
use std::mem;
use std::time::{Duration, Instant};
use crate::messages::{BlobDescriptor, Event, Request, Response};
use crate::{Codec, Stream, Transport};
use serde_json::Value as JsonValue;
use thiserror::Error;
#[derive(Debug)]
pub struct BaseStreams<T> {
pub rpc: T,
pub blob: T,
pub event: T,
}
#[derive(Debug)]
pub struct BaseCodec<S, T: Transport<Streams = BaseStreams<S>>> {
transport: T,
rpc: BufReader<S>,
blob: S,
event: BufReader<S>,
partial_resp: Vec<u8>,
partial_event: Vec<u8>,
}
impl<S: Stream, T: Transport<Streams = BaseStreams<S>>> BaseCodec<S, T> {
pub fn new(mut transport: T) -> Result<Self, T::Error> {
let streams = transport.open_streams()?;
Ok(Self {
transport,
rpc: BufReader::new(streams.rpc),
blob: streams.blob,
event: BufReader::new(streams.event),
partial_resp: Vec::new(),
partial_event: Vec::new(),
})
}
fn reopen_streams(&mut self) -> Result<(), BaseCodecError<T::Error>> {
let streams = self
.transport
.open_streams()
.map_err(BaseCodecError::Transport)?;
self.rpc = BufReader::new(streams.rpc);
self.blob = streams.blob;
self.event = BufReader::new(streams.event);
self.partial_resp.clear();
self.partial_event.clear();
Ok(())
}
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum BaseCodecError<E: Error> {
#[error("I/O error: {0}")]
Io(#[from] io::Error),
#[error("Serde error: {0}")]
Serde(#[from] serde_json::Error),
#[error("Transport error: {0}")]
Transport(#[source] E),
#[error("Request too big")]
RequestTooBig,
#[error("Blob checksum invalid")]
BlobChecksumInvalid,
}
impl<S: Stream, T: Transport<Streams = BaseStreams<S>>> BaseCodec<S, T> {
fn send_request_raw(
&mut self,
request: &Request,
blobs: &[&[u8]],
) -> Result<(), <Self as Codec>::Error> {
let mut buf = Vec::new();
buf.push(0);
serde_json::to_writer(&mut buf, &request)?;
buf.push(0);
if buf.len() > 4096 {
return Err(BaseCodecError::RequestTooBig);
}
for blob in blobs {
self.blob.write_all(blob)?;
}
self.rpc.get_mut().write_all(&buf)?;
Ok(())
}
fn read_response_raw(
&mut self,
timeout: Option<Duration>,
) -> Result<Option<Response>, <Self as Codec>::Error> {
let deadline = timeout.map(|x| Instant::now() + x);
loop {
let remaining = deadline.map(|d| d.saturating_duration_since(Instant::now()));
if remaining == Some(Duration::ZERO) {
self.rpc.get_ref().set_nonblocking(true)?;
self.rpc.get_ref().set_read_timeout(None)?;
} else {
self.rpc.get_ref().set_nonblocking(false)?;
self.rpc.get_ref().set_read_timeout(remaining)?;
}
match self.rpc.read_until(0, &mut self.partial_resp) {
Ok(0) => {
self.reopen_streams()?;
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"EOF when reading response",
)
.into());
}
Ok(_) => (),
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock || e.kind() == io::ErrorKind::TimedOut
{
return Ok(None);
} else {
return Err(e.into());
}
}
}
if self.partial_resp.last() != Some(&0) {
continue;
}
self.partial_resp.pop();
let frame = mem::take(&mut self.partial_resp);
if frame.is_empty() {
continue;
}
if let Ok(value) = serde_json::from_slice::<JsonValue>(&frame) {
return Ok(Some(serde_json::from_value(value)?));
}
}
}
fn read_event_raw(
&mut self,
timeout: Option<Duration>,
) -> Result<Option<Event>, <Self as Codec>::Error> {
let deadline = timeout.map(|x| Instant::now() + x);
loop {
let remaining = deadline.map(|d| d.saturating_duration_since(Instant::now()));
if remaining == Some(Duration::ZERO) {
self.event.get_ref().set_nonblocking(true)?;
self.event.get_ref().set_read_timeout(None)?;
} else {
self.event.get_ref().set_nonblocking(false)?;
self.event.get_ref().set_read_timeout(remaining)?;
}
match self.event.read_until(0, &mut self.partial_event) {
Ok(0) => {
self.reopen_streams()?;
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"EOF when reading event",
)
.into());
}
Ok(_) => (),
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock || e.kind() == io::ErrorKind::TimedOut
{
return Ok(None);
} else {
return Err(e.into());
}
}
}
if self.partial_event.last() != Some(&0) {
continue;
}
self.partial_event.pop();
let frame = mem::take(&mut self.partial_event);
if frame.is_empty() {
continue;
}
if let Ok(event) = serde_json::from_slice::<Event>(&frame) {
return Ok(Some(event));
}
}
}
fn read_blob_raw(
&mut self,
descriptor: BlobDescriptor,
) -> Result<Vec<u8>, <Self as Codec>::Error> {
let mut buf = vec![0; descriptor.length as usize];
self.blob.read_exact(&mut buf)?;
if !descriptor.verify_checksum(&buf) {
return Err(BaseCodecError::BlobChecksumInvalid);
}
Ok(buf)
}
}
impl<S: Stream, T: Transport<Streams = BaseStreams<S>>> Codec for BaseCodec<S, T> {
type Error = BaseCodecError<T::Error>;
fn send_request(&mut self, request: Request, blobs: &[&[u8]]) -> Result<(), Self::Error> {
match self.send_request_raw(&request, blobs) {
Ok(()) => Ok(()),
Err(BaseCodecError::Io(e)) => {
if e.kind() == io::ErrorKind::BrokenPipe {
self.reopen_streams()?;
}
Err(BaseCodecError::Io(e))
}
Err(e) => Err(e),
}
}
fn read_response(
&mut self,
timeout: Option<Duration>,
) -> Result<Option<Response>, Self::Error> {
match self.read_response_raw(timeout) {
Ok(x) => Ok(x),
Err(BaseCodecError::Io(e)) => {
if e.kind() == io::ErrorKind::BrokenPipe {
self.reopen_streams()?;
}
Err(BaseCodecError::Io(e))
}
Err(e) => Err(e),
}
}
fn read_event(&mut self, timeout: Option<Duration>) -> Result<Option<Event>, Self::Error> {
match self.read_event_raw(timeout) {
Ok(x) => Ok(x),
Err(BaseCodecError::Io(e)) => {
if e.kind() == io::ErrorKind::BrokenPipe {
self.reopen_streams()?;
self.read_event(timeout)
} else {
Err(BaseCodecError::Io(e))
}
}
Err(e) => Err(e),
}
}
fn read_blob(&mut self, descriptor: BlobDescriptor) -> Result<Vec<u8>, Self::Error> {
match self.read_blob_raw(descriptor) {
Ok(x) => Ok(x),
Err(BaseCodecError::Io(e)) => {
if e.kind() == io::ErrorKind::BrokenPipe {
self.reopen_streams()?;
}
Err(BaseCodecError::Io(e))
}
Err(e) => Err(e),
}
}
fn clear_response_stream(&mut self) -> Result<(), Self::Error> {
self.partial_resp.clear();
self.rpc.get_ref().set_nonblocking(true)?;
let mut buf = [0; 4096];
loop {
match self.rpc.read(&mut buf) {
Ok(amount_read) => {
if amount_read == 0 {
self.reopen_streams()?;
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"EOF when clearing response stream",
)
.into());
}
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
} else if e.kind() == io::ErrorKind::BrokenPipe {
self.reopen_streams()?;
}
return Err(e.into());
}
}
}
self.rpc.get_ref().set_nonblocking(false)?;
Ok(())
}
fn clear_blob_stream(&mut self) -> Result<(), Self::Error> {
self.blob.set_nonblocking(true)?;
let mut buf = [0; 4096];
loop {
match self.blob.read(&mut buf) {
Ok(amount_read) => {
if amount_read == 0 {
self.reopen_streams()?;
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"EOF when clearing blob stream",
)
.into());
}
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
} else if e.kind() == io::ErrorKind::BrokenPipe {
self.reopen_streams()?;
}
return Err(e.into());
}
}
}
self.blob.set_nonblocking(false)?;
Ok(())
}
}