implement Network Handler Logic

This commit is contained in:
CodeSteak 2019-04-24 19:24:00 +02:00
parent ca4fde0b50
commit 0e06fb1df4
5 changed files with 165 additions and 29 deletions

View File

@ -11,6 +11,8 @@ use crate::model::*;
mod protocol_connection;
use self::protocol_connection::*;
use super::results::*;
pub fn listen_forever<H>(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<H>(connection: TcpStream, handler: H) -> io::Result<()>
fn client_loop<H>(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))?;
}
}
}
}
}

View File

@ -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<ProtocolError> 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<ProtocolResult<Vec<Texture>>> for Package {
fn from(item: ProtocolResult<Vec<Texture>>) -> Self {
match item {
Ok(textures) => Package::JsonTextureArray(textures),
Err(err) => Package::from(err),
}
}
}
impl From<ProtocolResult<Option<Texture>>> for Package {
fn from(item: ProtocolResult<Option<Texture>>) -> Self {
match item {
Ok(Some(texture)) => Package::JsonTexture(texture),
Ok(None) => Package::JsonNull,
Err(err) => Package::from(err),
}
}
}
impl From<ProtocolResult<Vec<u8>>> for Package {
fn from(item: ProtocolResult<Vec<u8>>) -> 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<BufReader<TcpStream>, BufWriter<TcpStream>> {
impl Connection<BufReader<TcpStream>, 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 })
Ok(Connection {
reader,
writer: connection,
})
}
}

View File

@ -17,13 +17,17 @@ use std::sync::Arc;
pub trait ProtocolHandler: Send + Sync + Clone {
fn query(&mut self, query: &[String]) -> ProtocolResult<Vec<Texture>>;
fn get_texture_by_id(&mut self, id: String) -> ProtocolResult<Option<Texture>>;
fn get_texture_by_id(&mut self, id: &str) -> ProtocolResult<Option<Texture>>;
fn get_texture_by_name(&mut self, id: String) -> ProtocolResult<Option<Texture>>;
fn get_texture_by_name(&mut self, name: &str) -> ProtocolResult<Option<Texture>>;
fn get_texture_file(&mut self, hash: Sha256) -> ProtocolResult<Arc<Vec<u8>>>;
fn get_texture_file(&mut self, hash: Sha256) -> ProtocolResult<Vec<u8>>;
fn get_texture_preview(&mut self, hash: Sha256) -> ProtocolResult<Arc<Vec<u8>>>;
fn get_texture_preview(
&mut self,
hash: Sha256,
format: TextureFormat,
) -> ProtocolResult<Vec<u8>>;
fn replace_texture(
&mut self,

View File

@ -1,6 +1,8 @@
use crate::model::*;
pub enum ReplaceTextureStatus {
// Call Again With Texture Binary
NeedTextureData,
NeedTextureData(Sha256),
// Done.
Ok,
}

View File

@ -18,19 +18,23 @@ impl ProtocolHandler for ServerState {
unimplemented!()
}
fn get_texture_by_id(&mut self, id: String) -> ProtocolResult<Option<Texture>> {
fn get_texture_by_id(&mut self, id: &str) -> ProtocolResult<Option<Texture>> {
unimplemented!()
}
fn get_texture_by_name(&mut self, id: String) -> ProtocolResult<Option<Texture>> {
fn get_texture_by_name(&mut self, name: &str) -> ProtocolResult<Option<Texture>> {
unimplemented!()
}
fn get_texture_file(&mut self, hash: Sha256) -> ProtocolResult<Arc<Vec<u8>>> {
fn get_texture_file(&mut self, hash: Sha256) -> ProtocolResult<Vec<u8>> {
unimplemented!()
}
fn get_texture_preview(&mut self, hash: Sha256) -> ProtocolResult<Arc<Vec<u8>>> {
fn get_texture_preview(
&mut self,
hash: Sha256,
format: TextureFormat,
) -> ProtocolResult<Vec<u8>> {
unimplemented!()
}
@ -40,6 +44,7 @@ impl ProtocolHandler for ServerState {
insert: Option<Texture>,
insert_texture_data: Option<Vec<u8>>,
) -> ProtocolResult<ReplaceTextureStatus> {
// NOTE: must also check if insert_texture_data fits sha256!
unimplemented!()
}
}