file upload functionality
This commit is contained in:
parent
aae3ccfc2b
commit
d31e3429f1
|
@ -8,6 +8,7 @@ services:
|
||||||
bfile:
|
bfile:
|
||||||
volumes:
|
volumes:
|
||||||
- './filed:/opt/code'
|
- './filed:/opt/code'
|
||||||
|
- './volatile/files:/opt/user_uploads'
|
||||||
caddy:
|
caddy:
|
||||||
image: caddy:alpine
|
image: caddy:alpine
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
@ -8,5 +8,5 @@ use crate::env::Env;
|
||||||
|
|
||||||
pub fn redis_conn(env: Env) -> Result<Client, RedisError> {
|
pub fn redis_conn(env: Env) -> Result<Client, RedisError> {
|
||||||
log::info!("Connecting to redis DB on {}", env.redis.host);
|
log::info!("Connecting to redis DB on {}", env.redis.host);
|
||||||
redis::Client::open(format!("redis://{}:{}/", env.redis.host, env.redis.port))
|
redis::Client::open(format!("redis://:{}@{}:{}/", env.redis.pass, env.redis.host, env.redis.port))
|
||||||
}
|
}
|
|
@ -7,7 +7,8 @@ use crate::env::Env;
|
||||||
|
|
||||||
use super::File;
|
use super::File;
|
||||||
|
|
||||||
pub struct FileFinder {
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct FileManager {
|
||||||
conn: Client,
|
conn: Client,
|
||||||
env: Env
|
env: Env
|
||||||
}
|
}
|
||||||
|
@ -17,9 +18,9 @@ pub enum LookupKind {
|
||||||
ByHash
|
ByHash
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileFinder {
|
impl FileManager {
|
||||||
pub fn new(conn: Client, env: Env) -> FileFinder {
|
pub fn new(conn: Client, env: Env) -> FileManager {
|
||||||
FileFinder { conn, env }
|
FileManager { conn, env }
|
||||||
}
|
}
|
||||||
fn find(self: &Self, key: String) -> Result<Option<File>, Box<dyn Error>> {
|
fn find(self: &Self, key: String) -> Result<Option<File>, Box<dyn Error>> {
|
||||||
let mut conn = self.conn.get_connection()?;
|
let mut conn = self.conn.get_connection()?;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
// this whole crate is just a boilerplate
|
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
use std::{sync::Arc, error::Error, ops::Add};
|
use std::{sync::Arc, error::Error, ops::Add};
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
forms.rs - All the forms
|
forms.rs - All the forms
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, string::FromUtf8Error};
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use warp::{Filter, reply::Reply, reject::Rejection, filters::multipart::FormData, http::StatusCode};
|
use warp::{Filter, reply::Reply, reject::Rejection, filters::multipart::FormData, http::StatusCode};
|
||||||
|
@ -11,7 +11,7 @@ use futures_util::TryStreamExt;
|
||||||
use bytes::BufMut;
|
use bytes::BufMut;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::files::File;
|
use crate::files::{File, lookup::LookupKind};
|
||||||
|
|
||||||
use super::{state::SharedState, pages::BadActionReq, rejection::HttpReject};
|
use super::{state::SharedState, pages::BadActionReq, rejection::HttpReject};
|
||||||
|
|
||||||
|
@ -20,8 +20,13 @@ struct FormElement {
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
mime: String
|
mime: String
|
||||||
}
|
}
|
||||||
|
impl FormElement {
|
||||||
|
pub fn as_str_or_reject(self: &Self) -> Result<String, Rejection> {
|
||||||
|
Ok(String::from_utf8(self.data.clone()).map_err(|err| warp::reject::custom(HttpReject::FromUtf8Error(err)))?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn upload(form: FormData, _state: SharedState) -> Result<Box<dyn Reply>, Rejection> {
|
pub async fn upload(form: FormData, state: SharedState) -> Result<Box<dyn Reply>, Rejection> {
|
||||||
|
|
||||||
let params: HashMap<String, FormElement> = form.and_then(|mut field| async move {
|
let params: HashMap<String, FormElement> = form.and_then(|mut field| async move {
|
||||||
let mut bytes: Vec<u8> = vec![];
|
let mut bytes: Vec<u8> = vec![];
|
||||||
|
@ -60,24 +65,37 @@ pub async fn upload(form: FormData, _state: SharedState) -> Result<Box<dyn Reply
|
||||||
let delmode = params.get("delmode").unwrap();
|
let delmode = params.get("delmode").unwrap();
|
||||||
let named = params.get("named");
|
let named = params.get("named");
|
||||||
let filename = params.get("filename").unwrap();
|
let filename = params.get("filename").unwrap();
|
||||||
|
let mut is_named = named.is_none();
|
||||||
|
|
||||||
|
if named.is_some() {
|
||||||
|
is_named = named.unwrap().as_str_or_reject()? == "on";
|
||||||
|
}
|
||||||
|
|
||||||
let file = File::create(
|
let file = File::create(
|
||||||
data.data.clone(),
|
data.data.clone(),
|
||||||
data.mime.clone(),
|
data.mime.clone(),
|
||||||
match named {
|
match named {
|
||||||
Some(named) => {
|
Some(named) => {
|
||||||
if String::from_utf8(named.data.clone())
|
if named.as_str_or_reject()?
|
||||||
.map_err(|err| warp::reject::custom(HttpReject::FromUtf8Error(err)))?
|
|
||||||
.to_string() == "on" {
|
.to_string() == "on" {
|
||||||
Some(String::from_utf8(filename.data.clone()).map_err(|err| warp::reject::custom(HttpReject::FromUtf8Error(err)))?)
|
Some(filename.as_str_or_reject()?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => None
|
None => None
|
||||||
},
|
},
|
||||||
_state.env.clone()
|
state.env.clone()
|
||||||
).await;
|
).await
|
||||||
|
.map_err(|err| warp::reject::custom(HttpReject::StringError(err.to_string())))?;
|
||||||
|
|
||||||
|
state.file_mgr.save(&file, {
|
||||||
|
if is_named {
|
||||||
|
LookupKind::ByName
|
||||||
|
} else {
|
||||||
|
LookupKind::ByHash
|
||||||
|
}
|
||||||
|
}).map_err(|err| warp::reject::custom(HttpReject::StringError(err.to_string())))?;
|
||||||
|
|
||||||
Ok(Box::new(warp::reply::json(¶ms)))
|
Ok(Box::new(warp::reply::json(¶ms)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::env::current_dir;
|
||||||
|
|
||||||
use warp::{Filter, reply::Reply, reject::Rejection};
|
use warp::{Filter, reply::Reply, reject::Rejection};
|
||||||
|
|
||||||
use crate::env::Env;
|
use crate::{env::Env, files::lookup::FileManager};
|
||||||
|
|
||||||
mod pages;
|
mod pages;
|
||||||
mod forms;
|
mod forms;
|
||||||
|
@ -31,9 +31,11 @@ pub async fn serve(env: Env) {
|
||||||
|
|
||||||
log::info!("Listening on {}", env.listen.to_string());
|
log::info!("Listening on {}", env.listen.to_string());
|
||||||
|
|
||||||
|
let redis_cli = crate::db::redis_conn(env.clone()).unwrap();
|
||||||
let state = SharedState {
|
let state = SharedState {
|
||||||
redis_cli: crate::db::redis_conn(env.clone()).unwrap(),
|
redis_cli: redis_cli.clone(),
|
||||||
env: env.clone()
|
env: env.clone(),
|
||||||
|
file_mgr: FileManager::new(redis_cli, env.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
warp::serve(routes(state)).run(env.listen).await;
|
warp::serve(routes(state)).run(env.listen).await;
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::string::FromUtf8Error;
|
||||||
pub enum HttpReject {
|
pub enum HttpReject {
|
||||||
WarpError(warp::Error),
|
WarpError(warp::Error),
|
||||||
AskamaError(askama::Error),
|
AskamaError(askama::Error),
|
||||||
FromUtf8Error(FromUtf8Error)
|
FromUtf8Error(FromUtf8Error),
|
||||||
|
StringError(String)
|
||||||
}
|
}
|
||||||
impl warp::reject::Reject for HttpReject {}
|
impl warp::reject::Reject for HttpReject {}
|
|
@ -1,10 +1,11 @@
|
||||||
|
|
||||||
use redis::Client;
|
use redis::Client;
|
||||||
|
|
||||||
use crate::env::Env;
|
use crate::{env::Env, files::lookup::FileManager};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SharedState {
|
pub struct SharedState {
|
||||||
pub redis_cli: Client,
|
pub redis_cli: Client,
|
||||||
pub env: Env
|
pub env: Env,
|
||||||
|
pub file_mgr: FileManager
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue