use std::{
io::{self, Read, Write},
net::TcpStream,
};
use serde::{Deserialize, Serialize};
use crate::bencode;
pub enum Op {
Clone,
Close,
Eval,
}
impl std::str::FromStr for Op {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"clone" => Ok(Op::Clone),
"close" => Ok(Op::Close),
"eval" => Ok(Op::Eval),
_ => Err("invalid operation"),
}
}
}
impl std::fmt::Display for Op {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
fmt,
"{}",
match *self {
Op::Clone => "clone",
Op::Close => "close",
Op::Eval => "eval",
}
)
}
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct WireRequest {
pub op: String,
pub id: String,
pub session: Option<String>,
pub ns: Option<String>,
pub code: Option<String>,
pub line: Option<i32>,
pub column: Option<i32>,
pub file: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Response {
pub session: String,
pub id: Option<String>,
pub status: Option<Vec<String>>,
pub new_session: Option<String>,
pub value: Option<String>,
pub ex: Option<String>,
pub root_ex: Option<String>,
pub out: Option<String>,
pub err: Option<String>,
}
impl Response {
pub fn has_status(&self, label: &str) -> bool {
if let Some(ref ss) = self.status {
for s in ss.iter() {
if s == label {
return true;
}
}
}
false
}
}
pub struct Connection {
stream: TcpStream,
buffer: Vec<u8>,
}
impl Connection {
pub fn new(stream: TcpStream) -> Self {
Self {
stream,
buffer: Default::default(),
}
}
pub fn send(&mut self, request: &WireRequest) -> Result<(), io::Error> {
let payload = serde_bencode::to_bytes(request).unwrap();
self.stream.write_all(&payload)?;
self.stream.flush()
}
pub fn try_recv(&mut self) -> Result<Response, RecvError> {
let mut buffer = [0_u8; 4096];
loop {
match bencode::scan_next(&self.buffer) {
Ok((_, len)) => {
let response = {
let input = &self.buffer[0..len];
let response: Response =
serde_bencode::from_bytes(input).unwrap();
response
};
self.buffer.copy_within(len.., 0);
self.buffer.truncate(self.buffer.len() - len);
return Ok(response);
}
Err(bencode::Error::UnexpectedEnd) => (),
Err(bencode::Error::BadInput) => {
return Err(RecvError::BadInput)
}
}
let bytes_read = self.stream.read(&mut buffer)?;
self.buffer.extend_from_slice(&buffer[0..bytes_read]);
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum RecvError {
#[error("IO error")]
Io(#[from] io::Error),
#[error("bad input")]
BadInput,
}