TextureSync/server/texture-sync-server/src/protocol/implementation/protocol_connection.rs

305 lines
8.8 KiB
Rust

use crate::model::*;
use serde::{Deserialize, Serialize};
#[derive(Eq, PartialEq, Clone, Debug)]
pub enum Package {
JsonNull,
JsonFalse,
JsonTrue,
Json(Command),
Binary(Vec<u8>),
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<String> },
#[serde(rename = "get_texture")]
GetTexture {
id: Option<String>,
name: Option<String>,
},
#[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<Texture>,
new: Option<Texture>,
},
}
use std::io::*;
use std::net::*;
pub struct Connection<R: Read + Sized, W: Write + Sized> {
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<BufReader<TcpStream>, BufWriter<TcpStream>> {
pub fn from_tcp(connection: TcpStream) -> Result<Self> {
let reader = BufReader::new(connection.try_clone()?);
let writer = BufWriter::new(connection);
Ok(Connection { reader, writer })
}
}
impl<R: Read + Sized, W: Write + Sized> Connection<R, W> {
#[cfg(test)]
pub fn new(reader: R, writer: W) -> Self {
Connection { reader, writer }
}
pub fn receive(&mut self) -> Result<Package> {
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::<Option<bool>>(&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);
}
}