Isolate error handling from Warp
This commit is contained in:
parent
5535632466
commit
0f42ebcc30
|
@ -1,14 +1,32 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::{hash_map::Iter, HashMap},
|
collections::{hash_map::Iter, HashMap},
|
||||||
fmt::{self, Display},
|
fmt::{self, Display},
|
||||||
|
io::Read,
|
||||||
};
|
};
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
enum Error {
|
pub enum Error {
|
||||||
#[error("Asset could not be found: {0}")]
|
#[error("Asset could not be found")]
|
||||||
AssetNotFound(AssetId),
|
NotFound,
|
||||||
|
#[error("Asset could not be opened")]
|
||||||
|
Inaccessible,
|
||||||
|
|
||||||
|
#[error("An unexpected IO error occured when retrieving an asset {0}")]
|
||||||
|
UnexpectedError(std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for Error {
|
||||||
|
fn from(err: std::io::Error) -> Error {
|
||||||
|
use std::io::ErrorKind::*;
|
||||||
|
|
||||||
|
match err.kind() {
|
||||||
|
NotFound => Error::NotFound,
|
||||||
|
PermissionDenied | UnexpectedEof => Error::Inaccessible,
|
||||||
|
_ => Error::UnexpectedError(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
|
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
|
@ -70,7 +88,14 @@ impl Assets for FsAssets {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, asset_id: AssetId) -> Result<Vec<u8>, Error> {
|
fn get(&self, asset_id: AssetId) -> Result<Vec<u8>, Error> {
|
||||||
unimplemented!()
|
let path = match self.assets.get(&asset_id) {
|
||||||
|
Some(asset) => Ok(asset),
|
||||||
|
None => Err(Error::NotFound),
|
||||||
|
}?;
|
||||||
|
let mut content: Vec<u8> = Vec::new();
|
||||||
|
let mut file = std::fs::File::open(&path)?;
|
||||||
|
file.read_to_end(&mut content)?;
|
||||||
|
Ok(content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use urlencoding::decode;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
asset_db::{AssetId, Assets},
|
asset_db::{self, AssetId, Assets},
|
||||||
types::{AppError, Message, Tabletop, RGB},
|
types::{AppError, Message, Tabletop, RGB},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,19 +82,14 @@ impl Core {
|
||||||
self.0.read().unwrap().tabletop.clone()
|
self.0.read().unwrap().tabletop.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_file(&self, file_name: String) -> Vec<u8> {
|
pub async fn get_asset(&self, asset_id: AssetId) -> Result<Vec<u8>, AppError> {
|
||||||
/*
|
self.0.read().unwrap().asset_db.get(asset_id.clone()).map_err(|err| {
|
||||||
let file_name = decode(&file_name).expect("UTF-8");
|
match err {
|
||||||
|
asset_db::Error::NotFound => AppError::NotFound(format!("{}", asset_id)),
|
||||||
let mut full_path = self.0.read().unwrap().image_base.clone();
|
asset_db::Error::Inaccessible => AppError::Inaccessible(format!("{}", asset_id)),
|
||||||
full_path.push(file_name.to_string());
|
asset_db::Error::UnexpectedError(err) => AppError::Inaccessible(format!("{}", err)),
|
||||||
|
}
|
||||||
let mut content: Vec<u8> = Vec::new();
|
})
|
||||||
let mut file = std::fs::File::open(&full_path).unwrap();
|
|
||||||
file.read_to_end(&mut content).unwrap();
|
|
||||||
content
|
|
||||||
*/
|
|
||||||
unimplemented!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn available_images(&self) -> Vec<AssetId> {
|
pub fn available_images(&self) -> Vec<AssetId> {
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
use futures::{SinkExt, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use warp::{http::Response, reply::Reply, ws::Message};
|
use warp::{http::Response, http::StatusCode, reply::Reply, ws::Message};
|
||||||
|
|
||||||
use crate::core::Core;
|
use crate::{asset_db::AssetId, core::Core, types::AppError};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
pub async fn handle_auth(
|
pub async fn handle_auth(
|
||||||
|
@ -28,24 +30,52 @@ pub async fn handle_auth(
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub async fn handle_file(core: Core, file_name: String) -> impl Reply {
|
pub async fn handler<F>(f: F) -> impl Reply
|
||||||
let mimetype = mime_guess::from_path(&file_name).first().unwrap();
|
where
|
||||||
let bytes = core.get_file(file_name).await;
|
F: Future<Output = Result<Response<Vec<u8>>, AppError>>,
|
||||||
Response::builder()
|
{
|
||||||
|
match f.await {
|
||||||
|
Ok(response) => response,
|
||||||
|
Err(AppError::NotFound(_)) => Response::builder()
|
||||||
|
.status(StatusCode::NOT_FOUND)
|
||||||
|
.body(vec![])
|
||||||
|
.unwrap(),
|
||||||
|
Err(_) => Response::builder()
|
||||||
|
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
.body(vec![])
|
||||||
|
.unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_file(core: Core, asset_id: AssetId) -> impl Reply {
|
||||||
|
handler(async move {
|
||||||
|
let mimetype = mime_guess::from_path(&format!("{}", asset_id))
|
||||||
|
.first()
|
||||||
|
.unwrap();
|
||||||
|
let bytes = core.get_asset(asset_id).await?;
|
||||||
|
Ok(Response::builder()
|
||||||
.header("application-type", mimetype.to_string())
|
.header("application-type", mimetype.to_string())
|
||||||
.body(bytes)
|
.body(bytes)
|
||||||
.unwrap()
|
.unwrap())
|
||||||
|
})
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_available_images(core: Core) -> impl Reply {
|
pub async fn handle_available_images(core: Core) -> impl Reply {
|
||||||
let image_paths: Vec<String> = core.available_images().into_iter()
|
handler(async move {
|
||||||
.map(|path| format!("{}", path)).collect();
|
let image_paths: Vec<String> = core
|
||||||
|
.available_images()
|
||||||
|
.into_iter()
|
||||||
|
.map(|path| format!("{}", path))
|
||||||
|
.collect();
|
||||||
|
|
||||||
Response::builder()
|
Ok(Response::builder()
|
||||||
.header("Access-Control-Allow-Origin", "*")
|
.header("Access-Control-Allow-Origin", "*")
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
.body(serde_json::to_string(&image_paths).unwrap())
|
.body(serde_json::to_vec(&image_paths).unwrap())
|
||||||
.unwrap()
|
.unwrap())
|
||||||
|
})
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
|
@ -57,24 +87,30 @@ pub struct RegisterResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_register_client(core: Core, _request: RegisterRequest) -> impl Reply {
|
pub async fn handle_register_client(core: Core, _request: RegisterRequest) -> impl Reply {
|
||||||
|
handler(async move {
|
||||||
let client_id = core.register_client();
|
let client_id = core.register_client();
|
||||||
|
|
||||||
Response::builder()
|
Ok(Response::builder()
|
||||||
.header("Access-Control-Allow-Origin", "*")
|
.header("Access-Control-Allow-Origin", "*")
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
.body(
|
.body(
|
||||||
serde_json::to_string(&RegisterResponse {
|
serde_json::to_vec(&RegisterResponse {
|
||||||
url: format!("ws://127.0.0.1:8001/ws/{}", client_id),
|
url: format!("ws://127.0.0.1:8001/ws/{}", client_id),
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap())
|
||||||
|
})
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_unregister_client(core: Core, client_id: String) -> impl Reply {
|
pub async fn handle_unregister_client(core: Core, client_id: String) -> impl Reply {
|
||||||
|
handler(async move {
|
||||||
core.unregister_client(client_id);
|
core.unregister_client(client_id);
|
||||||
|
|
||||||
warp::reply::reply()
|
Ok(Response::builder().status(StatusCode::NO_CONTENT).body(vec![]).unwrap())
|
||||||
|
})
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_connect_websocket(
|
pub async fn handle_connect_websocket(
|
||||||
|
@ -109,12 +145,15 @@ pub async fn handle_connect_websocket(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_set_background_image(core: Core, image_name: String) -> impl Reply {
|
pub async fn handle_set_background_image(core: Core, image_name: String) -> impl Reply {
|
||||||
|
handler(async move {
|
||||||
let _ = core.set_background_image(image_name);
|
let _ = core.set_background_image(image_name);
|
||||||
|
|
||||||
Response::builder()
|
Ok(Response::builder()
|
||||||
.header("Access-Control-Allow-Origin", "*")
|
.header("Access-Control-Allow-Origin", "*")
|
||||||
.header("Access-Control-Allow-Methods", "*")
|
.header("Access-Control-Allow-Methods", "*")
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
.body("")
|
.body(vec![])
|
||||||
.unwrap()
|
.unwrap())
|
||||||
|
})
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use asset_db::FsAssets;
|
use asset_db::{AssetId, FsAssets};
|
||||||
use authdb::AuthError;
|
use authdb::AuthError;
|
||||||
use handlers::{
|
use handlers::{
|
||||||
handle_available_images, handle_connect_websocket, handle_file, handle_register_client, handle_set_background_image, handle_unregister_client, RegisterRequest
|
handle_available_images, handle_connect_websocket, handle_file, handle_register_client, handle_set_background_image, handle_unregister_client, RegisterRequest
|
||||||
|
@ -103,7 +103,7 @@ pub async fn main() {
|
||||||
.and(warp::get())
|
.and(warp::get())
|
||||||
.then({
|
.then({
|
||||||
let core = core.clone();
|
let core = core.clone();
|
||||||
move |file_name| handle_file(core.clone(), file_name)
|
move |file_name| handle_file(core.clone(), AssetId::from(file_name))
|
||||||
});
|
});
|
||||||
|
|
||||||
let route_available_images = warp::path!("api" / "v1" / "image").and(warp::get()).then({
|
let route_available_images = warp::path!("api" / "v1" / "image").and(warp::get()).then({
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use typeshare::typeshare;
|
use typeshare::typeshare;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AppError {
|
pub enum AppError {
|
||||||
NotFound(String),
|
NotFound(String),
|
||||||
|
Inaccessible(String),
|
||||||
JsonError(serde_json::Error),
|
JsonError(serde_json::Error),
|
||||||
|
UnexpectedError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
|
Loading…
Reference in New Issue