implement Network Handler Logic
This commit is contained in:
		@ -11,6 +11,8 @@ use crate::model::*;
 | 
				
			|||||||
mod protocol_connection;
 | 
					mod protocol_connection;
 | 
				
			||||||
use self::protocol_connection::*;
 | 
					use self::protocol_connection::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::results::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn listen_forever<H>(handler: H, config: &ProtocolConfig) -> io::Result<()>
 | 
					pub fn listen_forever<H>(handler: H, config: &ProtocolConfig) -> io::Result<()>
 | 
				
			||||||
where
 | 
					where
 | 
				
			||||||
    H: 'static + ProtocolHandler + Sized,
 | 
					    H: 'static + ProtocolHandler + Sized,
 | 
				
			||||||
@ -26,37 +28,34 @@ where
 | 
				
			|||||||
            stream.set_write_timeout(Duration::from_secs(config.read_timeout_s).into())
 | 
					            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));
 | 
					        let _ = thread::spawn(move || client_loop(connection?, handler));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn client_loop<H>(connection: TcpStream, handler: H) -> io::Result<()>
 | 
					fn client_loop<H>(connection: TcpStream, mut handler: H) -> io::Result<()>
 | 
				
			||||||
where
 | 
					where
 | 
				
			||||||
    H: 'static + ProtocolHandler + Sized,
 | 
					    H: 'static + ProtocolHandler + Sized,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    let mut connection = Connection::from_tcp(connection)?;
 | 
					    let mut connection = Connection::from_tcp(connection)?;
 | 
				
			||||||
    loop {
 | 
					    'outer: loop {
 | 
				
			||||||
        let package = connection.receive()?;
 | 
					        let package = connection.receive()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        match package {
 | 
					        match package {
 | 
				
			||||||
            Package::Error(_, _) => {
 | 
					            Package::Error(_, _) => {
 | 
				
			||||||
                // Just clone the connection.
 | 
					                // Just close the connection.
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Package::Binary(_) => {
 | 
					            Package::JsonTrue
 | 
				
			||||||
                connection.send(&Package::Error(400, "Unexpected Binary".to_string()))?;
 | 
					            | Package::JsonFalse
 | 
				
			||||||
                break;
 | 
					            | Package::JsonNull
 | 
				
			||||||
            }
 | 
					            | Package::JsonTexture(_)
 | 
				
			||||||
 | 
					            | Package::JsonTextureArray(_)
 | 
				
			||||||
            Package::JsonTrue | Package::JsonFalse | Package::JsonNull => {
 | 
					            | Package::Binary(_) => {
 | 
				
			||||||
                connection.send(&Package::Error(
 | 
					                connection.send(&Package::Error(400, "Expected Command.".to_string()))?;
 | 
				
			||||||
                    400,
 | 
					 | 
				
			||||||
                    "Unexpected true, false or null. ".to_string(),
 | 
					 | 
				
			||||||
                ))?;
 | 
					 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -68,8 +67,81 @@ where
 | 
				
			|||||||
                // Ignore
 | 
					                // Ignore
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // TODO: lots
 | 
					            Package::Json(Command::Query { query }) => {
 | 
				
			||||||
            _ => unimplemented!(),
 | 
					                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))?;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,8 @@ use crate::model::*;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: put conversion and these enums in own file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Eq, PartialEq, Clone, Debug)]
 | 
					#[derive(Eq, PartialEq, Clone, Debug)]
 | 
				
			||||||
pub enum Package {
 | 
					pub enum Package {
 | 
				
			||||||
    JsonNull,
 | 
					    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::io::*;
 | 
				
			||||||
use std::net::*;
 | 
					use std::net::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -56,12 +108,13 @@ const PACKAGE_TYPE_ERROR: u8 = 0;
 | 
				
			|||||||
const PACKAGE_TYPE_JSON: u8 = 1;
 | 
					const PACKAGE_TYPE_JSON: u8 = 1;
 | 
				
			||||||
const PACKAGE_TYPE_BIN: u8 = 2;
 | 
					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> {
 | 
					    pub fn from_tcp(connection: TcpStream) -> Result<Self> {
 | 
				
			||||||
        let reader = BufReader::new(connection.try_clone()?);
 | 
					        let reader = BufReader::new(connection.try_clone()?);
 | 
				
			||||||
        let writer = BufWriter::new(connection);
 | 
					        Ok(Connection {
 | 
				
			||||||
 | 
					            reader,
 | 
				
			||||||
        Ok(Connection { reader, writer })
 | 
					            writer: connection,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -17,13 +17,17 @@ use std::sync::Arc;
 | 
				
			|||||||
pub trait ProtocolHandler: Send + Sync + Clone {
 | 
					pub trait ProtocolHandler: Send + Sync + Clone {
 | 
				
			||||||
    fn query(&mut self, query: &[String]) -> ProtocolResult<Vec<Texture>>;
 | 
					    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(
 | 
					    fn replace_texture(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
 | 
					use crate::model::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub enum ReplaceTextureStatus {
 | 
					pub enum ReplaceTextureStatus {
 | 
				
			||||||
    // Call Again With Texture Binary
 | 
					    // Call Again With Texture Binary
 | 
				
			||||||
    NeedTextureData,
 | 
					    NeedTextureData(Sha256),
 | 
				
			||||||
    // Done.
 | 
					    // Done.
 | 
				
			||||||
    Ok,
 | 
					    Ok,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -18,19 +18,23 @@ impl ProtocolHandler for ServerState {
 | 
				
			|||||||
        unimplemented!()
 | 
					        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!()
 | 
					        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!()
 | 
					        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!()
 | 
					        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!()
 | 
					        unimplemented!()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -40,6 +44,7 @@ impl ProtocolHandler for ServerState {
 | 
				
			|||||||
        insert: Option<Texture>,
 | 
					        insert: Option<Texture>,
 | 
				
			||||||
        insert_texture_data: Option<Vec<u8>>,
 | 
					        insert_texture_data: Option<Vec<u8>>,
 | 
				
			||||||
    ) -> ProtocolResult<ReplaceTextureStatus> {
 | 
					    ) -> ProtocolResult<ReplaceTextureStatus> {
 | 
				
			||||||
 | 
					        // NOTE: must also check if insert_texture_data fits sha256!
 | 
				
			||||||
        unimplemented!()
 | 
					        unimplemented!()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user