restructre server network files
This commit is contained in:
		@ -1,106 +1,10 @@
 | 
				
			|||||||
use crate::model::*;
 | 
					use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: put conversion and these enums in own file.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Eq, PartialEq, Clone, Debug)]
 | 
					 | 
				
			||||||
pub enum Package {
 | 
					 | 
				
			||||||
    Json(JsonValue),
 | 
					 | 
				
			||||||
    Command(Command),
 | 
					 | 
				
			||||||
    Binary(Vec<u8>),
 | 
					 | 
				
			||||||
    Error(u16, String),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Eq, PartialEq, Clone, Debug)]
 | 
					 | 
				
			||||||
pub enum JsonValue {
 | 
					 | 
				
			||||||
    Null,
 | 
					 | 
				
			||||||
    True,
 | 
					 | 
				
			||||||
    False,
 | 
					 | 
				
			||||||
    Texture(Texture),
 | 
					 | 
				
			||||||
    TextureArray(Vec<Texture>),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[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 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::Json(JsonValue::TextureArray(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::Json(JsonValue::Texture(texture)),
 | 
					 | 
				
			||||||
            Ok(None) => Package::Json(JsonValue::Null),
 | 
					 | 
				
			||||||
            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::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Connection<R: Read + Sized, W: Write + Sized> {
 | 
					pub struct Connection<R: Read + Sized, W: Write + Sized> {
 | 
				
			||||||
    reader: R,
 | 
					    reader: R,
 | 
				
			||||||
    writer: W,
 | 
					    writer: W,
 | 
				
			||||||
@ -0,0 +1,137 @@
 | 
				
			|||||||
 | 
					use std::io::*;
 | 
				
			||||||
 | 
					use std::net::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::thread;
 | 
				
			||||||
 | 
					use std::time::Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn listen_forever<H>(handler: H, config: &ProtocolConfig) -> io::Result<()>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        H: 'static + ProtocolHandler + Sized,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let listener = TcpListener::bind((config.listen_addr.as_str(), config.port))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for mut connection in listener.incoming() {
 | 
				
			||||||
 | 
					        // If there is an successful connection,
 | 
				
			||||||
 | 
					        // set timeouts.
 | 
				
			||||||
 | 
					        // We ignore errors here, so they will be caught in the clients thread.
 | 
				
			||||||
 | 
					        let _ = connection.as_mut().map(|stream| {
 | 
				
			||||||
 | 
					            stream.set_read_timeout(Duration::from_secs(config.read_timeout_s).into())?;
 | 
				
			||||||
 | 
					            stream.set_write_timeout(Duration::from_secs(config.read_timeout_s).into())
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let handler = handler.clone();
 | 
				
			||||||
 | 
					        let _ = thread::spawn(move || client_loop(connection?, handler));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn client_loop<H>(connection: TcpStream, mut handler: H) -> io::Result<()>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        H: 'static + ProtocolHandler + Sized,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let mut connection = Connection::from_tcp(connection)?;
 | 
				
			||||||
 | 
					    'outer: loop {
 | 
				
			||||||
 | 
					        let package = connection.receive()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        match package {
 | 
				
			||||||
 | 
					            Package::Error(_, _) => {
 | 
				
			||||||
 | 
					                // Just close the connection.
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Package::Json(_) | Package::Binary(_) => {
 | 
				
			||||||
 | 
					                connection.send(&Package::Error(400, "Expected Command.".to_string()))?;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Package::Command(Command::Ping {}) => {
 | 
				
			||||||
 | 
					                connection.send(&Package::Command(Command::Pong {}))?;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Package::Command(Command::Pong {}) => {
 | 
				
			||||||
 | 
					                // Ignore
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Package::Command(Command::Query { query }) => {
 | 
				
			||||||
 | 
					                connection.send(&Package::from(handler.query(&query[..])))?;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Package::Command(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::Command(Command::GetTextureData { texture_hash }) => {
 | 
				
			||||||
 | 
					                connection.send(&Package::from(handler.get_texture_file(texture_hash)))?;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Package::Command(Command::GetTexturePreview {
 | 
				
			||||||
 | 
					                                 texture_hash,
 | 
				
			||||||
 | 
					                                 desired_format,
 | 
				
			||||||
 | 
					                             }) => {
 | 
				
			||||||
 | 
					                connection.send(&Package::from(
 | 
				
			||||||
 | 
					                    handler.get_texture_preview(texture_hash, desired_format),
 | 
				
			||||||
 | 
					                ))?;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // TODO: use less nesting.
 | 
				
			||||||
 | 
					            Package::Command(Command::ReplaceTexture { old, new }) => {
 | 
				
			||||||
 | 
					                match handler.replace_texture(old.clone(), new.clone(), None) {
 | 
				
			||||||
 | 
					                    Ok(ReplaceTextureStatus::Ok) => {
 | 
				
			||||||
 | 
					                        connection.send(&Package::Json(JsonValue::True))?;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    Ok(ReplaceTextureStatus::NeedTextureData(hash)) => {
 | 
				
			||||||
 | 
					                        connection.send(&Package::Command(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::Json(JsonValue::True))?;
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        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))?;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,144 +1,10 @@
 | 
				
			|||||||
use super::*;
 | 
					use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::io::*;
 | 
					mod connection;
 | 
				
			||||||
use std::net::*;
 | 
					use self::connection::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::thread;
 | 
					mod listen_forever;
 | 
				
			||||||
use std::time::Duration;
 | 
					pub use self::listen_forever::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::model::*;
 | 
					mod package;
 | 
				
			||||||
 | 
					use self::package::*;
 | 
				
			||||||
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,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    let listener = TcpListener::bind((config.listen_addr.as_str(), config.port))?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for mut connection in listener.incoming() {
 | 
					 | 
				
			||||||
        // If there is an successful connection,
 | 
					 | 
				
			||||||
        // set timeouts.
 | 
					 | 
				
			||||||
        // We ignore errors here, so they will be caught in the clients thread.
 | 
					 | 
				
			||||||
        let _ = connection.as_mut().map(|stream| {
 | 
					 | 
				
			||||||
            stream.set_read_timeout(Duration::from_secs(config.read_timeout_s).into())?;
 | 
					 | 
				
			||||||
            stream.set_write_timeout(Duration::from_secs(config.read_timeout_s).into())
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let handler = handler.clone();
 | 
					 | 
				
			||||||
        let _ = thread::spawn(move || client_loop(connection?, handler));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Ok(())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn client_loop<H>(connection: TcpStream, mut handler: H) -> io::Result<()>
 | 
					 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    H: 'static + ProtocolHandler + Sized,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    let mut connection = Connection::from_tcp(connection)?;
 | 
					 | 
				
			||||||
    'outer: loop {
 | 
					 | 
				
			||||||
        let package = connection.receive()?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        match package {
 | 
					 | 
				
			||||||
            Package::Error(_, _) => {
 | 
					 | 
				
			||||||
                // Just close the connection.
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Package::Json(_) | Package::Binary(_) => {
 | 
					 | 
				
			||||||
                connection.send(&Package::Error(400, "Expected Command.".to_string()))?;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Package::Command(Command::Ping {}) => {
 | 
					 | 
				
			||||||
                connection.send(&Package::Command(Command::Pong {}))?;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Package::Command(Command::Pong {}) => {
 | 
					 | 
				
			||||||
                // Ignore
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Package::Command(Command::Query { query }) => {
 | 
					 | 
				
			||||||
                connection.send(&Package::from(handler.query(&query[..])))?;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Package::Command(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::Command(Command::GetTextureData { texture_hash }) => {
 | 
					 | 
				
			||||||
                connection.send(&Package::from(handler.get_texture_file(texture_hash)))?;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Package::Command(Command::GetTexturePreview {
 | 
					 | 
				
			||||||
                texture_hash,
 | 
					 | 
				
			||||||
                desired_format,
 | 
					 | 
				
			||||||
            }) => {
 | 
					 | 
				
			||||||
                connection.send(&Package::from(
 | 
					 | 
				
			||||||
                    handler.get_texture_preview(texture_hash, desired_format),
 | 
					 | 
				
			||||||
                ))?;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // TODO: use less nesting.
 | 
					 | 
				
			||||||
            Package::Command(Command::ReplaceTexture { old, new }) => {
 | 
					 | 
				
			||||||
                match handler.replace_texture(old.clone(), new.clone(), None) {
 | 
					 | 
				
			||||||
                    Ok(ReplaceTextureStatus::Ok) => {
 | 
					 | 
				
			||||||
                        connection.send(&Package::Json(JsonValue::True))?;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    Ok(ReplaceTextureStatus::NeedTextureData(hash)) => {
 | 
					 | 
				
			||||||
                        connection.send(&Package::Command(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::Json(JsonValue::True))?;
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                    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))?;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Ok(())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					use crate::model::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Eq, PartialEq, Clone, Debug)]
 | 
				
			||||||
 | 
					pub enum Package {
 | 
				
			||||||
 | 
					    Json(JsonValue),
 | 
				
			||||||
 | 
					    Command(Command),
 | 
				
			||||||
 | 
					    Binary(Vec<u8>),
 | 
				
			||||||
 | 
					    Error(u16, String),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Eq, PartialEq, Clone, Debug)]
 | 
				
			||||||
 | 
					pub enum JsonValue {
 | 
				
			||||||
 | 
					    Null,
 | 
				
			||||||
 | 
					    True,
 | 
				
			||||||
 | 
					    False,
 | 
				
			||||||
 | 
					    Texture(Texture),
 | 
				
			||||||
 | 
					    TextureArray(Vec<Texture>),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[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 super::error::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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::Json(JsonValue::TextureArray(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::Json(JsonValue::Texture(texture)),
 | 
				
			||||||
 | 
					            Ok(None) => Package::Json(JsonValue::Null),
 | 
				
			||||||
 | 
					            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),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,13 +1,8 @@
 | 
				
			|||||||
// TODO: remove on implementation
 | 
					mod error;
 | 
				
			||||||
#![allow(unused_imports)]
 | 
					pub use self::error::*;
 | 
				
			||||||
#![allow(unused_variables)]
 | 
					 | 
				
			||||||
#![allow(dead_code)]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mod results;
 | 
					 | 
				
			||||||
pub use self::results::*;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod implementation;
 | 
					mod implementation;
 | 
				
			||||||
pub use self::implementation::listen_forever;
 | 
					pub use self::implementation::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::model::*;
 | 
					use crate::model::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user