use crate::model::*; use serde::{Deserialize, Serialize}; #[derive(Eq, PartialEq, Clone, Debug)] pub enum Package { JsonNull, JsonFalse, JsonTrue, Json(Command), Binary(Vec), Error(u16, String), } #[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug)] pub enum Command { #[serde(rename = "ping")] Ping {}, #[serde(rename = "pong")] Pong {}, #[serde(rename = "query")] Query { query: Vec }, #[serde(rename = "get_texture")] GetTexture { id: Option, name: Option, }, #[serde(rename = "get_texture_file")] GetTextureData { texture_hash: Sha256 }, #[serde(rename = "get_texture_preview")] GetTexturePreview { texture_hash: Sha256, desired_format: TextureFormat, }, #[serde(rename = "replace_texture")] ReplaceTexture { old: Option, new: Option, }, } use std::io::*; use std::net::*; pub struct Connection { reader: R, writer: W, } const KIB: u32 = 1024; const MIB: u32 = 1024 * 1024; const PACKAGE_TYPE_ERROR: u8 = 0; const PACKAGE_TYPE_JSON: u8 = 1; const PACKAGE_TYPE_BIN: u8 = 2; impl Connection, BufWriter> { pub fn from_tcp(connection: TcpStream) -> Result { let reader = BufReader::new(connection.try_clone()?); let writer = BufWriter::new(connection); Ok(Connection { reader, writer }) } } impl Connection { #[cfg(test)] pub fn new(reader: R, writer: W) -> Self { Connection { reader, writer } } pub fn receive(&mut self) -> Result { let mut payload_type_buffer = [0u8; 1]; let mut reserved_buffer = [0u8; 3]; let mut payload_length_buffer = [0u8; 4]; self.reader.read_exact(&mut payload_type_buffer)?; self.reader.read_exact(&mut reserved_buffer)?; self.reader.read_exact(&mut payload_length_buffer)?; let payload_type = payload_type_buffer[0]; let payload_length = u32::from_be_bytes(payload_length_buffer); // Check length. match payload_type { PACKAGE_TYPE_ERROR => { if payload_length > 1 * KIB { return Err(Error::new( ErrorKind::InvalidData, "Maximum length of Error Package is 1 KiB.", )); } } PACKAGE_TYPE_JSON => { if payload_length > 16 * MIB { return Err(Error::new( ErrorKind::InvalidData, "Maximum length of JSON Package is 16 MiB.", )); } } PACKAGE_TYPE_BIN => { if payload_length > 512 * MIB { return Err(Error::new( ErrorKind::InvalidData, "Maximum length of Binary Package is 512 MiB.", )); } } _ => { return Err(Error::new(ErrorKind::InvalidData, "Unknown Package Type.")); } } let mut payload = vec![0u8; payload_length as usize]; self.reader.read_exact(&mut payload[..])?; match payload_type { PACKAGE_TYPE_ERROR => { let contents = String::from_utf8(payload) .map_err(|_| Error::new(ErrorKind::InvalidData, "Invalid UTF-8."))?; let mut parts = contents.splitn(2, " "); match (parts.next(), parts.next()) { (Some(code), Some(info)) => { let code: u16 = code.parse().map_err(|_| { Error::new(ErrorKind::InvalidData, "Status code in error expected!") })?; Ok(Package::Error(code, info.to_string())) } _ => Err(Error::new( ErrorKind::InvalidData, "Status code in error expected!", )), } } PACKAGE_TYPE_JSON => { // try special packages first. match serde_json::from_slice::>(&payload[..]) { Ok(Some(true)) => { return Ok(Package::JsonTrue); } Ok(Some(false)) => { return Ok(Package::JsonFalse); } Ok(None) => { return Ok(Package::JsonNull); } _ => (), // else try other } let json: Command = serde_json::from_slice(&payload[..]).map_err(|e| { #[cfg(test)] dbg!(&e); Error::new(ErrorKind::InvalidData, "Invalid JSON.") })?; Ok(Package::Json(json)) } PACKAGE_TYPE_BIN => Ok(Package::Binary(payload)), _ => { // Covered in the match above. unreachable!(); } } } pub fn send(&mut self, pkg: &Package) -> Result<()> { unimplemented!() } } #[cfg(test)] mod test { use super::*; #[test] fn read_error_good() { let mut read_data = Vec::new(); let msg = b"42 TEST"; read_data.extend_from_slice(&[0, 42, 42, 42, 0, 0, 0, msg.len() as u8]); read_data.extend_from_slice(msg); let mut c = Connection::new(&read_data[..], Vec::new()); assert_eq!(c.receive().unwrap(), Package::Error(42, "TEST".to_string())) } #[test] fn read_error_bad() { let mut read_data = Vec::new(); let msg = b"TEST XXXX"; read_data.extend_from_slice(&[0, 42, 42, 42, 0, 0, 0, msg.len() as u8]); read_data.extend_from_slice(msg); let mut c = Connection::new(&read_data[..], Vec::new()); assert_eq!(c.receive().is_err(), true) } #[test] fn read_binary_good() { let mut read_data = Vec::new(); let msg = b"Hello World"; read_data.extend_from_slice(&[2, 42, 42, 42, 0, 0, 0, msg.len() as u8]); read_data.extend_from_slice(msg); let mut c = Connection::new(&read_data[..], Vec::new()); assert_eq!(c.receive().unwrap(), Package::Binary(Vec::from(&msg[..]))); } #[test] fn read_binary_bad() { let mut read_data = Vec::new(); let msg = b"Hello World"; // to large (size). read_data.extend_from_slice(&[2, 42, 42, 42, 255, 0, 0, 0]); read_data.extend_from_slice(msg); let mut c = Connection::new(&read_data[..], Vec::new()); assert_eq!(c.receive().is_err(), true); } // we don't test the actual json parsing here, // since serde_json is well tested. // AndTesting the declaration seams not worth the effort. #[test] fn read_json_good() { let mut read_data = Vec::new(); let msg = br#"{ "query" : { "query" : ["Hallo", "Welt!"] } }"#; read_data.extend_from_slice(&[1, 42, 42, 42, 0, 0, 0, msg.len() as u8]); read_data.extend_from_slice(msg); let mut c = Connection::new(&read_data[..], Vec::new()); assert_eq!( c.receive().unwrap(), Package::Json(Command::Query { query: vec!["Hallo".to_string(), "Welt!".to_string()], }) ); } #[test] fn read_json_multiple_special() { let mut read_data = Vec::new(); let msg = br#"null"#; read_data.extend_from_slice(&[1, 42, 42, 42, 0, 0, 0, msg.len() as u8]); read_data.extend_from_slice(msg); let msg = br#"true"#; read_data.extend_from_slice(&[1, 42, 42, 42, 0, 0, 0, msg.len() as u8]); read_data.extend_from_slice(msg); let msg = br#"false"#; read_data.extend_from_slice(&[1, 42, 42, 42, 0, 0, 0, msg.len() as u8]); read_data.extend_from_slice(msg); let mut c = Connection::new(&read_data[..], Vec::new()); assert_eq!(c.receive().unwrap(), Package::JsonNull); assert_eq!(c.receive().unwrap(), Package::JsonTrue); assert_eq!(c.receive().unwrap(), Package::JsonFalse); } #[test] fn read_json_bad() { let mut read_data = Vec::new(); let msg = br#"{ "big foot" : { "query" : ["Hallo", "Welt!"] } }"#; read_data.extend_from_slice(&[1, 42, 42, 42, 0, 0, 0, msg.len() as u8]); read_data.extend_from_slice(msg); let mut c = Connection::new(&read_data[..], Vec::new()); assert_eq!(c.receive().is_err(), true); } }