Set up automated tests for the application Core #266
|
@ -1,14 +1,32 @@
|
|||
use std::{
|
||||
collections::{hash_map::Iter, HashMap},
|
||||
fmt::{self, Display},
|
||||
io::Read,
|
||||
};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum Error {
|
||||
#[error("Asset could not be found: {0}")]
|
||||
AssetNotFound(AssetId),
|
||||
pub enum Error {
|
||||
#[error("Asset could not be found")]
|
||||
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)]
|
||||
|
@ -70,7 +88,14 @@ impl Assets for FsAssets {
|
|||
}
|
||||
|
||||
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 crate::{
|
||||
asset_db::{AssetId, Assets},
|
||||
asset_db::{self, AssetId, Assets},
|
||||
types::{AppError, Message, Tabletop, RGB},
|
||||
};
|
||||
|
||||
|
@ -82,19 +82,14 @@ impl Core {
|
|||
self.0.read().unwrap().tabletop.clone()
|
||||
}
|
||||
|
||||
pub async fn get_file(&self, file_name: String) -> Vec<u8> {
|
||||
/*
|
||||
let file_name = decode(&file_name).expect("UTF-8");
|
||||
|
||||
let mut full_path = self.0.read().unwrap().image_base.clone();
|
||||
full_path.push(file_name.to_string());
|
||||
|
||||
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 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| {
|
||||
match err {
|
||||
asset_db::Error::NotFound => AppError::NotFound(format!("{}", asset_id)),
|
||||
asset_db::Error::Inaccessible => AppError::Inaccessible(format!("{}", asset_id)),
|
||||
asset_db::Error::UnexpectedError(err) => AppError::Inaccessible(format!("{}", err)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn available_images(&self) -> Vec<AssetId> {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use std::future::Future;
|
||||
|
||||
use futures::{SinkExt, StreamExt};
|
||||
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(
|
||||
|
@ -28,24 +30,52 @@ pub async fn handle_auth(
|
|||
}
|
||||
*/
|
||||
|
||||
pub async fn handle_file(core: Core, file_name: String) -> impl Reply {
|
||||
let mimetype = mime_guess::from_path(&file_name).first().unwrap();
|
||||
let bytes = core.get_file(file_name).await;
|
||||
Response::builder()
|
||||
pub async fn handler<F>(f: F) -> impl Reply
|
||||
where
|
||||
F: Future<Output = Result<Response<Vec<u8>>, AppError>>,
|
||||
{
|
||||
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())
|
||||
.body(bytes)
|
||||
.unwrap()
|
||||
.unwrap())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn handle_available_images(core: Core) -> impl Reply {
|
||||
let image_paths: Vec<String> = core.available_images().into_iter()
|
||||
.map(|path| format!("{}", path)).collect();
|
||||
handler(async move {
|
||||
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("Content-Type", "application/json")
|
||||
.body(serde_json::to_string(&image_paths).unwrap())
|
||||
.unwrap()
|
||||
.body(serde_json::to_vec(&image_paths).unwrap())
|
||||
.unwrap())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
|
@ -57,24 +87,30 @@ pub struct RegisterResponse {
|
|||
}
|
||||
|
||||
pub async fn handle_register_client(core: Core, _request: RegisterRequest) -> impl Reply {
|
||||
handler(async move {
|
||||
let client_id = core.register_client();
|
||||
|
||||
Response::builder()
|
||||
Ok(Response::builder()
|
||||
.header("Access-Control-Allow-Origin", "*")
|
||||
.header("Content-Type", "application/json")
|
||||
.body(
|
||||
serde_json::to_string(&RegisterResponse {
|
||||
serde_json::to_vec(&RegisterResponse {
|
||||
url: format!("ws://127.0.0.1:8001/ws/{}", client_id),
|
||||
})
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn handle_unregister_client(core: Core, client_id: String) -> impl Reply {
|
||||
handler(async move {
|
||||
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(
|
||||
|
@ -109,12 +145,15 @@ pub async fn handle_connect_websocket(
|
|||
}
|
||||
|
||||
pub async fn handle_set_background_image(core: Core, image_name: String) -> impl Reply {
|
||||
handler(async move {
|
||||
let _ = core.set_background_image(image_name);
|
||||
|
||||
Response::builder()
|
||||
Ok(Response::builder()
|
||||
.header("Access-Control-Allow-Origin", "*")
|
||||
.header("Access-Control-Allow-Methods", "*")
|
||||
.header("Content-Type", "application/json")
|
||||
.body("")
|
||||
.unwrap()
|
||||
.body(vec![])
|
||||
.unwrap())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use asset_db::FsAssets;
|
||||
use asset_db::{AssetId, FsAssets};
|
||||
use authdb::AuthError;
|
||||
use handlers::{
|
||||
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())
|
||||
.then({
|
||||
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({
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use typeshare::typeshare;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AppError {
|
||||
NotFound(String),
|
||||
Inaccessible(String),
|
||||
JsonError(serde_json::Error),
|
||||
UnexpectedError(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
|
|
Loading…
Reference in New Issue