WIP
This commit is contained in:
663
api/src/lib.rs
663
api/src/lib.rs
File diff suppressed because it is too large
Load Diff
128
api/src/main.rs
128
api/src/main.rs
@@ -1,11 +1,5 @@
|
||||
use std::convert::Infallible;
|
||||
|
||||
use serde::Serialize;
|
||||
use uuid::Uuid;
|
||||
use warp::http::StatusCode;
|
||||
use warp::Filter;
|
||||
|
||||
use packager;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum TripItemStatus {
|
||||
@@ -95,87 +89,51 @@ impl<'a> Trip<'a> {
|
||||
// println!("{:?}", item);
|
||||
// }
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ErrorMessage {
|
||||
code: u16,
|
||||
success: bool,
|
||||
message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InvalidUuid;
|
||||
|
||||
impl warp::reject::Reject for InvalidUuid {}
|
||||
|
||||
// See https://github.com/seanmonstar/warp/blob/master/examples/rejections.rs
|
||||
async fn handle_rejection(err: warp::Rejection) -> Result<impl warp::Reply, Infallible> {
|
||||
let code;
|
||||
let message;
|
||||
|
||||
if err.is_not_found() {
|
||||
message = "NOT_FOUND";
|
||||
code = StatusCode::NOT_FOUND;
|
||||
} else if let Some(InvalidUuid) = err.find() {
|
||||
code = StatusCode::BAD_REQUEST;
|
||||
message = "INVALID_UUID";
|
||||
} else if let Some(e) = err.find::<warp::filters::body::BodyDeserializeError>() {
|
||||
message = "BAD_REQUEST";
|
||||
code = StatusCode::BAD_REQUEST;
|
||||
} else if let Some(_) = err.find::<warp::reject::MethodNotAllowed>() {
|
||||
message = "METHOD_NOT_ALLOWED";
|
||||
code = StatusCode::METHOD_NOT_ALLOWED;
|
||||
} else {
|
||||
// We should have expected this... Just log and say its a 500
|
||||
eprintln!("unhandled rejection: {:?}", err);
|
||||
message = "UNHANDLED_REJECTION";
|
||||
code = StatusCode::INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
let json = warp::reply::json(&ErrorMessage {
|
||||
success: false,
|
||||
code: code.as_u16(),
|
||||
message: message.into(),
|
||||
});
|
||||
|
||||
Ok(warp::reply::with_status(json, code))
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let accept_json = warp::header::exact("accept", "application/json");
|
||||
let cors = warp::cors().allow_any_origin();
|
||||
// let accept_json = warp::header::exact("accept", "application/json");
|
||||
// let cors = warp::cors().allow_any_origin();
|
||||
|
||||
let root = warp::path::end().map(|| "Hi");
|
||||
let v1 = warp::path!("v1")
|
||||
.and(warp::get())
|
||||
.and(warp::path::end())
|
||||
.map(warp::reply);
|
||||
let lists = warp::path!("v1" / "lists")
|
||||
.and(warp::path::end())
|
||||
.and(warp::get())
|
||||
.and(accept_json)
|
||||
.map(|| warp::reply::json(&packager::get_lists()))
|
||||
.with(&cors);
|
||||
let list = warp::path!("v1" / "lists" / String)
|
||||
.and(warp::path::end())
|
||||
.and(warp::get())
|
||||
.and(accept_json)
|
||||
.and_then(|id: String| async move {
|
||||
match Uuid::parse_str(&id) {
|
||||
Ok(uuid) => {
|
||||
let list = &packager::get_list(uuid);
|
||||
match list {
|
||||
Some(l) => Ok(warp::reply::json(l)),
|
||||
None => Err(warp::reject::not_found()),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(warp::reject::custom(InvalidUuid)),
|
||||
}
|
||||
})
|
||||
.with(&cors)
|
||||
.recover(handle_rejection);
|
||||
// let root = warp::path::end()
|
||||
// .map(|| "Hi")
|
||||
// .recover(packager::router::handle_rejection);
|
||||
|
||||
let routes = root.or(v1).or(lists).or(list);
|
||||
// let v1 = warp::path!("v1")
|
||||
// .and(warp::get())
|
||||
// .and(warp::path::end())
|
||||
// .map(warp::reply)
|
||||
// .recover(packager::router::handle_rejection);
|
||||
|
||||
warp::serve(routes).run(([127, 0, 0, 1], 9000)).await;
|
||||
// let lists = warp::path!("v1" / "lists")
|
||||
// .and(warp::path::end())
|
||||
// .and(warp::get())
|
||||
// .and(accept_json)
|
||||
// .map(|| warp::reply::json(&packager::get_lists()))
|
||||
// .with(&cors)
|
||||
// .recover(packager::router::handle_rejection);
|
||||
|
||||
// let list = warp::path!("v1" / "lists" / String)
|
||||
// .and(warp::path::end())
|
||||
// .and(warp::get())
|
||||
// .and(accept_json)
|
||||
// .and_then(|id: String| async move {
|
||||
// match Uuid::parse_str(&id) {
|
||||
// Ok(uuid) => {
|
||||
// let list = &packager::get_list(uuid);
|
||||
// match list {
|
||||
// Some(l) => Ok(warp::reply::json(l)),
|
||||
// None => Err(warp::reject::not_found()),
|
||||
// }
|
||||
// }
|
||||
// Err(e) => Err(warp::reject::custom(packager::router::InvalidUuid)),
|
||||
// }
|
||||
// })
|
||||
// .with(&cors)
|
||||
// .recover(packager::router::handle_rejection);
|
||||
|
||||
// let router = root.or(v1).or(lists).or(list);
|
||||
|
||||
let router = packager::router::new();
|
||||
|
||||
warp::serve(router).run(([127, 0, 0, 1], 9000)).await;
|
||||
}
|
||||
|
||||
226
api/src/packagelist.rs
Normal file
226
api/src/packagelist.rs
Normal file
@@ -0,0 +1,226 @@
|
||||
use serde::ser::{SerializeStruct, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Duration {
|
||||
None,
|
||||
Days(i32),
|
||||
}
|
||||
|
||||
impl Duration {
|
||||
pub fn is_none(d: &Duration) -> bool {
|
||||
matches!(d, Duration::None)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Period {
|
||||
Daily(i32),
|
||||
Weekly(i32),
|
||||
Days(i32),
|
||||
}
|
||||
|
||||
impl Serialize for Period {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self {
|
||||
Period::Daily(i) => {
|
||||
let mut s = serializer.serialize_struct("period", 2)?;
|
||||
s.serialize_field("type", "daily")?;
|
||||
s.serialize_field("value", &i)?;
|
||||
s.end()
|
||||
}
|
||||
Period::Weekly(i) => {
|
||||
let mut s = serializer.serialize_struct("period", 2)?;
|
||||
s.serialize_field("type", "weekly")?;
|
||||
s.serialize_field("value", &i)?;
|
||||
s.end()
|
||||
}
|
||||
Period::Days(i) => {
|
||||
let mut s = serializer.serialize_struct("period", 2)?;
|
||||
s.serialize_field("type", "days")?;
|
||||
s.serialize_field("value", &i)?;
|
||||
s.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ItemUsage {
|
||||
Singleton,
|
||||
Periodic(Period),
|
||||
Infinite,
|
||||
}
|
||||
|
||||
impl Serialize for ItemUsage {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self {
|
||||
ItemUsage::Singleton => {
|
||||
let mut s = serializer.serialize_struct("usage", 1)?;
|
||||
s.serialize_field("type", "singleton")?;
|
||||
s.end()
|
||||
}
|
||||
ItemUsage::Periodic(p) => {
|
||||
let mut s = serializer.serialize_struct("usage", 2)?;
|
||||
s.serialize_field("type", "peridoic")?;
|
||||
s.serialize_field("value", &p)?;
|
||||
s.end()
|
||||
}
|
||||
ItemUsage::Infinite => {
|
||||
let mut s = serializer.serialize_struct("size", 1)?;
|
||||
s.serialize_field("type", "infinite")?;
|
||||
s.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ItemSize {
|
||||
None,
|
||||
Pack(i32),
|
||||
Name(String),
|
||||
Gram(i32),
|
||||
}
|
||||
|
||||
impl Serialize for ItemSize {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self {
|
||||
ItemSize::None => {
|
||||
let mut s = serializer.serialize_struct("size", 1)?;
|
||||
s.serialize_field("type", "none")?;
|
||||
s.end()
|
||||
}
|
||||
ItemSize::Pack(i) => {
|
||||
let mut s = serializer.serialize_struct("size", 2)?;
|
||||
s.serialize_field("type", "pack")?;
|
||||
s.serialize_field("value", &i)?;
|
||||
s.end()
|
||||
}
|
||||
ItemSize::Name(n) => {
|
||||
let mut s = serializer.serialize_struct("size", 2)?;
|
||||
s.serialize_field("type", "name")?;
|
||||
s.serialize_field("value", &n)?;
|
||||
s.end()
|
||||
}
|
||||
ItemSize::Gram(i) => {
|
||||
let mut s = serializer.serialize_struct("size", 2)?;
|
||||
s.serialize_field("type", "gram")?;
|
||||
s.serialize_field("value", &i)?;
|
||||
s.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ItemSize {
|
||||
pub fn is_none(d: &ItemSize) -> bool {
|
||||
matches!(d, ItemSize::None)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PreparationStep {
|
||||
name: String,
|
||||
|
||||
#[serde(skip_serializing_if = "Duration::is_none")]
|
||||
start: Duration,
|
||||
}
|
||||
|
||||
impl PreparationStep {
|
||||
pub fn new(name: String, start: Duration) -> PreparationStep {
|
||||
PreparationStep { name, start }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Preparation {
|
||||
None,
|
||||
Steps(Vec<PreparationStep>),
|
||||
}
|
||||
|
||||
impl Preparation {
|
||||
pub fn is_none(d: &Preparation) -> bool {
|
||||
matches!(d, Preparation::None)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PackageItem {
|
||||
pub id: Uuid,
|
||||
name: String,
|
||||
|
||||
#[serde(skip_serializing_if = "ItemSize::is_none")]
|
||||
size: ItemSize,
|
||||
count: i32,
|
||||
usage: ItemUsage,
|
||||
|
||||
#[serde(skip_serializing_if = "Preparation::is_none")]
|
||||
preparation: Preparation,
|
||||
}
|
||||
|
||||
impl PackageItem {
|
||||
pub fn new(
|
||||
id: Uuid,
|
||||
name: String,
|
||||
size: ItemSize,
|
||||
count: i32,
|
||||
usage: ItemUsage,
|
||||
preparation: Preparation,
|
||||
) -> PackageItem {
|
||||
PackageItem {
|
||||
id,
|
||||
name,
|
||||
size,
|
||||
count,
|
||||
usage,
|
||||
preparation,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_simple(id: Uuid, name: String) -> PackageItem {
|
||||
PackageItem::new(
|
||||
id,
|
||||
name,
|
||||
ItemSize::None,
|
||||
1,
|
||||
ItemUsage::Singleton,
|
||||
Preparation::None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PackageList {
|
||||
pub id: Uuid,
|
||||
pub name: String,
|
||||
pub items: Vec<PackageItem>,
|
||||
}
|
||||
|
||||
impl PackageList {
|
||||
pub fn new_from_items(id: Uuid, name: String, items: Vec<PackageItem>) -> PackageList {
|
||||
PackageList { id, name, items }
|
||||
}
|
||||
}
|
||||
|
||||
96
api/src/router.rs
Normal file
96
api/src/router.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use std::convert::Infallible;
|
||||
use serde::Serialize;
|
||||
use warp;
|
||||
use warp::http::StatusCode;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InvalidUuid;
|
||||
|
||||
impl warp::reject::Reject for InvalidUuid {}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ErrorMessage {
|
||||
code: u16,
|
||||
success: bool,
|
||||
message: String,
|
||||
}
|
||||
|
||||
pub fn new() -> warp::filters::BoxedFilter<(impl warp::Reply,)> {
|
||||
let accept_json = warp::header::exact("accept", "application/json");
|
||||
let cors = warp::cors().allow_any_origin();
|
||||
|
||||
let root = warp::path::end()
|
||||
.map(|| "Hi")
|
||||
.recover(handle_rejection);
|
||||
|
||||
let v1 = warp::path!("v1")
|
||||
.and(warp::get())
|
||||
.and(warp::path::end())
|
||||
.map(warp::reply)
|
||||
.recover(handle_rejection);
|
||||
|
||||
let lists = warp::path!("v1" / "lists")
|
||||
.and(warp::path::end())
|
||||
.and(warp::get())
|
||||
.and(accept_json)
|
||||
.map(|| warp::reply::json(&super::get_lists()))
|
||||
.with(&cors)
|
||||
.recover(handle_rejection);
|
||||
|
||||
let list = warp::path!("v1" / "lists" / String)
|
||||
.and(warp::path::end())
|
||||
.and(warp::get())
|
||||
.and(accept_json)
|
||||
.and_then(|id: String| async move {
|
||||
match Uuid::parse_str(&id) {
|
||||
Ok(uuid) => {
|
||||
let list = &super::get_list(uuid);
|
||||
match list {
|
||||
Some(l) => Ok(warp::reply::json(l)),
|
||||
None => Err(warp::reject::not_found()),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(warp::reject::custom(InvalidUuid)),
|
||||
}
|
||||
})
|
||||
.with(&cors)
|
||||
.recover(handle_rejection);
|
||||
|
||||
let routes = root.or(v1).or(lists).or(list).boxed();
|
||||
|
||||
routes
|
||||
}
|
||||
|
||||
// See https://github.com/seanmonstar/warp/blob/master/examples/rejections.rs
|
||||
async fn handle_rejection(err: warp::Rejection) -> Result<impl warp::Reply, Infallible> {
|
||||
let code;
|
||||
let message;
|
||||
|
||||
if err.is_not_found() {
|
||||
message = "NOT_FOUND";
|
||||
code = StatusCode::NOT_FOUND;
|
||||
} else if let Some(InvalidUuid) = err.find() {
|
||||
code = StatusCode::BAD_REQUEST;
|
||||
message = "INVALID_UUID";
|
||||
} else if let Some(e) = err.find::<warp::filters::body::BodyDeserializeError>() {
|
||||
message = "BAD_REQUEST";
|
||||
code = StatusCode::BAD_REQUEST;
|
||||
} else if let Some(_) = err.find::<warp::reject::MethodNotAllowed>() {
|
||||
message = "METHOD_NOT_ALLOWED";
|
||||
code = StatusCode::METHOD_NOT_ALLOWED;
|
||||
} else {
|
||||
// We should have expected this... Just log and say its a 500
|
||||
eprintln!("unhandled rejection: {:?}", err);
|
||||
message = "UNHANDLED_REJECTION";
|
||||
code = StatusCode::INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
let json = warp::reply::json(&ErrorMessage {
|
||||
success: false,
|
||||
code: code.as_u16(),
|
||||
message: message.into(),
|
||||
});
|
||||
|
||||
Ok(warp::reply::with_status(json, code))
|
||||
}
|
||||
Reference in New Issue
Block a user