mirror of https://github.com/raftario/filite.git
First routes
This commit is contained in:
parent
41a745f82a
commit
bb4366100f
|
@ -278,6 +278,7 @@ dependencies = [
|
|||
"askama 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -19,6 +19,7 @@ anyhow = "1.0.32"
|
|||
askama = "0.10.3"
|
||||
base64 = "0.12.3"
|
||||
bincode = "1.3.1"
|
||||
bytes = "0.5.6"
|
||||
chrono = { version = "0.4.18", features = ["serde"] }
|
||||
futures = "0.3.5"
|
||||
rand = "0.7.3"
|
||||
|
|
|
@ -9,7 +9,7 @@ use sled::Db;
|
|||
use tokio::task;
|
||||
use warp::{Filter, Rejection};
|
||||
|
||||
pub fn auth_optional(
|
||||
pub fn optional(
|
||||
db: &'static Db,
|
||||
config: &'static Config,
|
||||
) -> impl Filter<Extract = (Option<User>,), Error = Rejection> + Copy + Send + Sync + 'static {
|
||||
|
@ -24,7 +24,7 @@ pub fn auth_optional(
|
|||
})
|
||||
}
|
||||
|
||||
pub fn auth_required(
|
||||
pub fn required(
|
||||
db: &'static Db,
|
||||
config: &'static Config,
|
||||
) -> impl Filter<Extract = (User,), Error = Rejection> + Copy + Send + Sync + 'static {
|
||||
|
|
|
@ -6,6 +6,9 @@ mod routes;
|
|||
mod runtime;
|
||||
mod util;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use anyhow::Error;
|
||||
use config::Config;
|
||||
use structopt::StructOpt;
|
||||
|
|
|
@ -1,24 +1,27 @@
|
|||
use std::fmt::Display;
|
||||
use std::fmt::{Debug, Display};
|
||||
use warp::{
|
||||
http::StatusCode,
|
||||
reject::{Reject, Rejection},
|
||||
reply::{Reply, Response},
|
||||
};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
enum FiliteRejection {
|
||||
NotFound,
|
||||
Unauthorized,
|
||||
InternalServerError,
|
||||
Conflict,
|
||||
|
||||
Custom(String, StatusCode),
|
||||
}
|
||||
impl Reject for FiliteRejection {}
|
||||
impl Reply for FiliteRejection {
|
||||
fn into_response(self) -> Response {
|
||||
match self {
|
||||
FiliteRejection::NotFound => {
|
||||
Self::NotFound => {
|
||||
warp::reply::with_status("Not Found", StatusCode::NOT_FOUND).into_response()
|
||||
}
|
||||
FiliteRejection::Unauthorized => warp::reply::with_status(
|
||||
Self::Unauthorized => warp::reply::with_status(
|
||||
warp::reply::with_header(
|
||||
"Unauthorized",
|
||||
"WWW-Authenticate",
|
||||
|
@ -27,10 +30,14 @@ impl Reply for FiliteRejection {
|
|||
StatusCode::UNAUTHORIZED,
|
||||
)
|
||||
.into_response(),
|
||||
FiliteRejection::InternalServerError => {
|
||||
Self::InternalServerError => {
|
||||
warp::reply::with_status("Internal Server Error", StatusCode::INTERNAL_SERVER_ERROR)
|
||||
.into_response()
|
||||
}
|
||||
Self::Conflict => {
|
||||
warp::reply::with_status("Conflict", StatusCode::CONFLICT).into_response()
|
||||
}
|
||||
Self::Custom(reply, status) => warp::reply::with_status(reply, status).into_response(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,10 +47,16 @@ pub fn unauthorized() -> Rejection {
|
|||
warp::reject::custom(FiliteRejection::Unauthorized)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn custom<T: ToString>(reply: T, status: StatusCode) -> Rejection {
|
||||
warp::reject::custom(FiliteRejection::Custom(reply.to_string(), status))
|
||||
}
|
||||
|
||||
pub trait TryExt<T> {
|
||||
fn or_404(self) -> Result<T, Rejection>;
|
||||
fn or_401(self) -> Result<T, Rejection>;
|
||||
fn or_500(self) -> Result<T, Rejection>;
|
||||
fn or_409(self) -> Result<T, Rejection>;
|
||||
}
|
||||
|
||||
impl<T, E: Display> TryExt<T> for Result<T, E> {
|
||||
|
@ -67,6 +80,13 @@ impl<T, E: Display> TryExt<T> for Result<T, E> {
|
|||
warp::reject::custom(FiliteRejection::InternalServerError)
|
||||
})
|
||||
}
|
||||
|
||||
fn or_409(self) -> Result<T, Rejection> {
|
||||
self.map_err(|e| {
|
||||
tracing::error!("{}", e);
|
||||
warp::reject::custom(FiliteRejection::Conflict)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TryExt<T> for Option<T> {
|
||||
|
@ -81,6 +101,10 @@ impl<T> TryExt<T> for Option<T> {
|
|||
fn or_500(self) -> Result<T, Rejection> {
|
||||
self.ok_or_else(|| warp::reject::custom(FiliteRejection::InternalServerError))
|
||||
}
|
||||
|
||||
fn or_409(self) -> Result<T, Rejection> {
|
||||
self.ok_or_else(|| warp::reject::custom(FiliteRejection::Conflict))
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug")]
|
||||
|
@ -88,7 +112,7 @@ pub async fn handle_rejections(err: Rejection) -> Result<impl Reply, Rejection>
|
|||
if err.is_not_found() {
|
||||
Ok(FiliteRejection::NotFound)
|
||||
} else if let Some(err) = err.find::<FiliteRejection>() {
|
||||
Ok(*err)
|
||||
Ok(err.clone())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
use crate::{config::Config, db::User, reject::TryExt};
|
||||
use bytes::Bytes;
|
||||
use sled::Db;
|
||||
use warp::{http::Uri, Filter, Rejection, Reply};
|
||||
|
||||
pub fn handler(
|
||||
config: &'static Config,
|
||||
db: &'static Db,
|
||||
) -> impl Filter<Extract = impl Reply, Error = Rejection> + Copy + Send + Sync + 'static {
|
||||
let filite = warp::path!(String)
|
||||
.and(warp::get())
|
||||
.and_then(move |id| filite(id, db));
|
||||
|
||||
let post_file = warp::path!("f")
|
||||
.and(warp::post())
|
||||
.and(crate::auth::required(db, config))
|
||||
.and(warp::body::bytes())
|
||||
.and(warp::header("Content-Type"))
|
||||
.and(warp::header::optional("X-ID-Length"))
|
||||
.and_then(move |user, data, mime, len| post_file(user, data, mime, len, db));
|
||||
let put_file = warp::path!("f" / String)
|
||||
.and(warp::put())
|
||||
.and(crate::auth::required(db, config))
|
||||
.and(warp::body::bytes())
|
||||
.and(warp::header("Content-Type"))
|
||||
.and_then(move |id, user, data, mime| put_file(id, user, data, mime, db));
|
||||
|
||||
let post_link = warp::path!("l")
|
||||
.and(warp::post())
|
||||
.and(crate::auth::required(db, config))
|
||||
.and(crate::util::body())
|
||||
.and(warp::header::optional("X-ID-Length"))
|
||||
.and_then(move |user, location, len| post_link(user, location, len, db));
|
||||
let put_link = warp::path!("l" / String)
|
||||
.and(warp::put())
|
||||
.and(crate::auth::required(db, config))
|
||||
.and(crate::util::body())
|
||||
.and_then(move |id, user, location| put_link(id, user, location, db));
|
||||
|
||||
let post_text = warp::path!("t")
|
||||
.and(warp::post())
|
||||
.and(crate::auth::required(db, config))
|
||||
.and(crate::util::body())
|
||||
.and(warp::header::optional("X-ID-Length"))
|
||||
.and_then(move |user, data, len| post_text(user, data, len, db));
|
||||
let put_text = warp::path!("t" / String)
|
||||
.and(warp::put())
|
||||
.and(crate::auth::required(db, config))
|
||||
.and(crate::util::body())
|
||||
.and_then(move |id, user, data| put_text(id, user, data, db));
|
||||
|
||||
filite
|
||||
.or(post_file)
|
||||
.or(put_file)
|
||||
.or(post_link)
|
||||
.or(put_link)
|
||||
.or(post_text)
|
||||
.or(put_text)
|
||||
}
|
||||
|
||||
async fn filite(id: String, db: &Db) -> Result<impl Reply, Rejection> {}
|
||||
|
||||
async fn post_file(
|
||||
user: User,
|
||||
data: Bytes,
|
||||
mime: String,
|
||||
len: Option<usize>,
|
||||
db: &Db,
|
||||
) -> Result<impl Reply, Rejection> {
|
||||
let id = crate::db::random_id(len.unwrap_or(8), db).or_500()?;
|
||||
put_file(id, user, data, mime, db).await
|
||||
}
|
||||
|
||||
async fn put_file(
|
||||
id: String,
|
||||
user: User,
|
||||
data: Bytes,
|
||||
mime: String,
|
||||
db: &Db,
|
||||
) -> Result<impl Reply, Rejection> {
|
||||
crate::db::insert_file(&id, user.id, data.to_vec(), mime, db)
|
||||
.or_500()?
|
||||
.or_409()?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
async fn post_link(
|
||||
user: User,
|
||||
location: Uri,
|
||||
len: Option<usize>,
|
||||
db: &Db,
|
||||
) -> Result<impl Reply, Rejection> {
|
||||
let id = crate::db::random_id(len.unwrap_or(8), db).or_500()?;
|
||||
put_link(id, user, location, db).await
|
||||
}
|
||||
|
||||
async fn put_link(id: String, user: User, location: Uri, db: &Db) -> Result<impl Reply, Rejection> {
|
||||
crate::db::insert_link(&id, user.id, location.to_string(), db)
|
||||
.or_500()?
|
||||
.or_409()?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
async fn post_text(
|
||||
user: User,
|
||||
data: String,
|
||||
len: Option<usize>,
|
||||
db: &Db,
|
||||
) -> Result<impl Reply, Rejection> {
|
||||
let id = crate::db::random_id(len.unwrap_or(8), db).or_500()?;
|
||||
put_text(id, user, data, db).await
|
||||
}
|
||||
|
||||
async fn put_text(id: String, user: User, data: String, db: &Db) -> Result<impl Reply, Rejection> {
|
||||
crate::db::insert_text(&id, user.id, data, db)
|
||||
.or_500()?
|
||||
.or_409()?;
|
||||
Ok(id)
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
// TODO
|
20
src/util.rs
20
src/util.rs
|
@ -1,3 +1,7 @@
|
|||
use bytes::Bytes;
|
||||
use std::str::FromStr;
|
||||
use warp::{http::StatusCode, Filter, Rejection};
|
||||
|
||||
pub trait DefaultExt {
|
||||
fn is_default(&self) -> bool;
|
||||
}
|
||||
|
@ -6,3 +10,19 @@ impl<T: Default + PartialEq> DefaultExt for T {
|
|||
self.eq(&Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn body<T>() -> impl Filter<Extract = (T,), Error = Rejection> + Copy + Send + Sync + 'static
|
||||
where
|
||||
T: FromStr,
|
||||
T::Err: ToString,
|
||||
{
|
||||
warp::body::bytes().and_then(|b: Bytes| async move {
|
||||
match std::str::from_utf8(&b) {
|
||||
Ok(s) => match s.parse() {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(crate::reject::custom(e, StatusCode::BAD_REQUEST)),
|
||||
},
|
||||
Err(e) => Err(crate::reject::custom(e, StatusCode::BAD_REQUEST)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue