implement Network Handler Logic
This commit is contained in:
parent
ca4fde0b50
commit
0e06fb1df4
@ -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!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user