From 0e06fb1df456fe262e1ffa11030c1a905edd53df Mon Sep 17 00:00:00 2001 From: CodeSteak Date: Wed, 24 Apr 2019 19:24:00 +0200 Subject: [PATCH] implement Network Handler Logic --- .../src/protocol/implementation/mod.rs | 104 +++++++++++++++--- .../implementation/protocol_connection.rs | 61 +++++++++- .../texture-sync-server/src/protocol/mod.rs | 12 +- .../src/protocol/results.rs | 4 +- .../texture-sync-server/src/server_state.rs | 13 ++- 5 files changed, 165 insertions(+), 29 deletions(-) diff --git a/server/texture-sync-server/src/protocol/implementation/mod.rs b/server/texture-sync-server/src/protocol/implementation/mod.rs index fe1d13e..89cbda3 100644 --- a/server/texture-sync-server/src/protocol/implementation/mod.rs +++ b/server/texture-sync-server/src/protocol/implementation/mod.rs @@ -11,6 +11,8 @@ use crate::model::*; mod protocol_connection; use self::protocol_connection::*; +use super::results::*; + pub fn listen_forever(handler: H, config: &ProtocolConfig) -> io::Result<()> where H: 'static + ProtocolHandler + Sized, @@ -26,37 +28,34 @@ where stream.set_write_timeout(Duration::from_secs(config.read_timeout_s).into()) }); - let mut handler = handler.clone(); + let handler = handler.clone(); let _ = thread::spawn(move || client_loop(connection?, handler)); } Ok(()) } -fn client_loop(connection: TcpStream, handler: H) -> io::Result<()> +fn client_loop(connection: TcpStream, mut handler: H) -> io::Result<()> where H: 'static + ProtocolHandler + Sized, { let mut connection = Connection::from_tcp(connection)?; - loop { + 'outer: loop { let package = connection.receive()?; match package { Package::Error(_, _) => { - // Just clone the connection. + // Just close the connection. break; } - Package::Binary(_) => { - connection.send(&Package::Error(400, "Unexpected Binary".to_string()))?; - break; - } - - Package::JsonTrue | Package::JsonFalse | Package::JsonNull => { - connection.send(&Package::Error( - 400, - "Unexpected true, false or null. ".to_string(), - ))?; + Package::JsonTrue + | Package::JsonFalse + | Package::JsonNull + | Package::JsonTexture(_) + | Package::JsonTextureArray(_) + | Package::Binary(_) => { + connection.send(&Package::Error(400, "Expected Command.".to_string()))?; break; } @@ -68,8 +67,81 @@ where // Ignore } - // TODO: lots - _ => unimplemented!(), + Package::Json(Command::Query { query }) => { + connection.send(&Package::from(handler.query(&query[..])))?; + } + + Package::Json(Command::GetTexture { id, name }) => match (id, name) { + (Some(id), None) => { + connection.send(&Package::from(handler.get_texture_by_id(&id)))?; + } + (None, Some(name)) => { + connection.send(&Package::from(handler.get_texture_by_name(&name)))?; + } + _ => { + connection.send(&Package::from(ProtocolError::BadRequest( + "Either 'id' or 'name' must be set!".to_string(), + )))?; + } + }, + + Package::Json(Command::GetTextureData { texture_hash }) => { + connection.send(&Package::from(handler.get_texture_file(texture_hash)))?; + } + + Package::Json(Command::GetTexturePreview { + texture_hash, + desired_format, + }) => { + connection.send(&Package::from( + handler.get_texture_preview(texture_hash, desired_format), + ))?; + } + + // TODO: use less nesting. + Package::Json(Command::ReplaceTexture { old, new }) => { + match handler.replace_texture(old.clone(), new.clone(), None) { + Ok(ReplaceTextureStatus::Ok) => { + connection.send(&Package::JsonTrue)?; + } + Ok(ReplaceTextureStatus::NeedTextureData(hash)) => { + connection.send(&Package::Json(Command::GetTextureData { + texture_hash: hash, + }))?; + + let pkg = connection.receive()?; + match pkg { + Package::Binary(data) => { + match handler.replace_texture(old.clone(), new.clone(), Some(data)) + { + Ok(ReplaceTextureStatus::Ok) => { + connection.send(&Package::JsonTrue)?; + } + Ok(ReplaceTextureStatus::NeedTextureData(hash)) => { + panic!("Contract Violation: handler must not return NeedTextureData \ + when data is given."); + } + Err(err) => { + connection.send(&Package::from(err))?; + } + } + } + Package::Error(_, _) => { + // Just close the connection. + break 'outer; + } + _ => { + connection.send(&Package::from(ProtocolError::BadRequest( + "Expected Texture Data!".to_string(), + )))?; + } + } + } + Err(err) => { + connection.send(&Package::from(err))?; + } + } + } } } diff --git a/server/texture-sync-server/src/protocol/implementation/protocol_connection.rs b/server/texture-sync-server/src/protocol/implementation/protocol_connection.rs index 502fec2..f2205cd 100644 --- a/server/texture-sync-server/src/protocol/implementation/protocol_connection.rs +++ b/server/texture-sync-server/src/protocol/implementation/protocol_connection.rs @@ -2,6 +2,8 @@ use crate::model::*; use serde::{Deserialize, Serialize}; +// TODO: put conversion and these enums in own file. + #[derive(Eq, PartialEq, Clone, Debug)] pub enum Package { JsonNull, @@ -41,6 +43,56 @@ pub enum Command { }, } +use super::results::*; + +impl From for Package { + fn from(item: ProtocolError) -> Self { + match item { + ProtocolError::BadRequest(msg) => Package::Error(400, msg), + ProtocolError::FileNotFound(msg) => Package::Error(404, msg), + ProtocolError::Conflict(msg) => Package::Error(409, msg), + ProtocolError::InternalServerError(_err) => { + Package::Error(500, "Internal Server Error.".to_string()) + } + ProtocolError::NotImplemented => Package::Error( + 501, + "Well, I'm sorry, \ + but this feature is still a Todo :/" + .to_string(), + ), + } + } +} + +impl From>> for Package { + fn from(item: ProtocolResult>) -> Self { + match item { + Ok(textures) => Package::JsonTextureArray(textures), + Err(err) => Package::from(err), + } + } +} + +impl From>> for Package { + fn from(item: ProtocolResult>) -> Self { + match item { + Ok(Some(texture)) => Package::JsonTexture(texture), + Ok(None) => Package::JsonNull, + Err(err) => Package::from(err), + } + } +} + +impl From>> for Package { + fn from(item: ProtocolResult>) -> Self { + match item { + Ok(bin) => Package::Binary(bin), + Err(err) => Package::from(err), + } + } +} + +use crate::protocol::results::ProtocolResult; use std::io::*; use std::net::*; @@ -56,12 +108,13 @@ const PACKAGE_TYPE_ERROR: u8 = 0; const PACKAGE_TYPE_JSON: u8 = 1; const PACKAGE_TYPE_BIN: u8 = 2; -impl Connection, BufWriter> { +impl Connection, TcpStream> { pub fn from_tcp(connection: TcpStream) -> Result { let reader = BufReader::new(connection.try_clone()?); - let writer = BufWriter::new(connection); - - Ok(Connection { reader, writer }) + Ok(Connection { + reader, + writer: connection, + }) } } diff --git a/server/texture-sync-server/src/protocol/mod.rs b/server/texture-sync-server/src/protocol/mod.rs index 2410501..d79564b 100644 --- a/server/texture-sync-server/src/protocol/mod.rs +++ b/server/texture-sync-server/src/protocol/mod.rs @@ -17,13 +17,17 @@ use std::sync::Arc; pub trait ProtocolHandler: Send + Sync + Clone { fn query(&mut self, query: &[String]) -> ProtocolResult>; - fn get_texture_by_id(&mut self, id: String) -> ProtocolResult>; + fn get_texture_by_id(&mut self, id: &str) -> ProtocolResult>; - fn get_texture_by_name(&mut self, id: String) -> ProtocolResult>; + fn get_texture_by_name(&mut self, name: &str) -> ProtocolResult>; - fn get_texture_file(&mut self, hash: Sha256) -> ProtocolResult>>; + fn get_texture_file(&mut self, hash: Sha256) -> ProtocolResult>; - fn get_texture_preview(&mut self, hash: Sha256) -> ProtocolResult>>; + fn get_texture_preview( + &mut self, + hash: Sha256, + format: TextureFormat, + ) -> ProtocolResult>; fn replace_texture( &mut self, diff --git a/server/texture-sync-server/src/protocol/results.rs b/server/texture-sync-server/src/protocol/results.rs index 8bc9a13..daecb0d 100644 --- a/server/texture-sync-server/src/protocol/results.rs +++ b/server/texture-sync-server/src/protocol/results.rs @@ -1,6 +1,8 @@ +use crate::model::*; + pub enum ReplaceTextureStatus { // Call Again With Texture Binary - NeedTextureData, + NeedTextureData(Sha256), // Done. Ok, } diff --git a/server/texture-sync-server/src/server_state.rs b/server/texture-sync-server/src/server_state.rs index 0b79ad3..24d41c0 100644 --- a/server/texture-sync-server/src/server_state.rs +++ b/server/texture-sync-server/src/server_state.rs @@ -18,19 +18,23 @@ impl ProtocolHandler for ServerState { unimplemented!() } - fn get_texture_by_id(&mut self, id: String) -> ProtocolResult> { + fn get_texture_by_id(&mut self, id: &str) -> ProtocolResult> { unimplemented!() } - fn get_texture_by_name(&mut self, id: String) -> ProtocolResult> { + fn get_texture_by_name(&mut self, name: &str) -> ProtocolResult> { unimplemented!() } - fn get_texture_file(&mut self, hash: Sha256) -> ProtocolResult>> { + fn get_texture_file(&mut self, hash: Sha256) -> ProtocolResult> { unimplemented!() } - fn get_texture_preview(&mut self, hash: Sha256) -> ProtocolResult>> { + fn get_texture_preview( + &mut self, + hash: Sha256, + format: TextureFormat, + ) -> ProtocolResult> { unimplemented!() } @@ -40,6 +44,7 @@ impl ProtocolHandler for ServerState { insert: Option, insert_texture_data: Option>, ) -> ProtocolResult { + // NOTE: must also check if insert_texture_data fits sha256! unimplemented!() } }