mirror of
https://github.com/amigan/rustypaste-pretty.git
synced 2025-01-31 13:02:43 -05:00
feat(paste): support disappearing (oneshot) files
This commit is contained in:
parent
3223c6379c
commit
73359f3534
3 changed files with 74 additions and 26 deletions
|
@ -15,7 +15,9 @@ async fn main() -> IoResult<()> {
|
||||||
.expect("failed to parse config");
|
.expect("failed to parse config");
|
||||||
let server_config = config.server.clone();
|
let server_config = config.server.clone();
|
||||||
fs::create_dir_all(&server_config.upload_path)?;
|
fs::create_dir_all(&server_config.upload_path)?;
|
||||||
fs::create_dir_all(PasteType::Url.get_path(&server_config.upload_path))?;
|
for paste_type in &[PasteType::Url, PasteType::Oneshot, PasteType::Trash] {
|
||||||
|
fs::create_dir_all(paste_type.get_path(&server_config.upload_path))?;
|
||||||
|
}
|
||||||
let mut http_server = HttpServer::new(move || {
|
let mut http_server = HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
.data(config.clone())
|
.data(config.clone())
|
||||||
|
|
46
src/paste.rs
46
src/paste.rs
|
@ -8,12 +8,16 @@ use std::str;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
/// Type of the data to store.
|
/// Type of the data to store.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub enum PasteType {
|
pub enum PasteType {
|
||||||
/// Any type of file.
|
/// Any type of file.
|
||||||
File,
|
File,
|
||||||
|
/// A file that allowed to be accessed once.
|
||||||
|
Oneshot,
|
||||||
/// A file that only contains an URL.
|
/// A file that only contains an URL.
|
||||||
Url,
|
Url,
|
||||||
|
/// A file that is expired or deleted.
|
||||||
|
Trash,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a ContentDisposition> for PasteType {
|
impl<'a> TryFrom<&'a ContentDisposition> for PasteType {
|
||||||
|
@ -21,6 +25,8 @@ impl<'a> TryFrom<&'a ContentDisposition> for PasteType {
|
||||||
fn try_from(content_disposition: &'a ContentDisposition) -> Result<Self, Self::Error> {
|
fn try_from(content_disposition: &'a ContentDisposition) -> Result<Self, Self::Error> {
|
||||||
if content_disposition.has_form_field("file") {
|
if content_disposition.has_form_field("file") {
|
||||||
Ok(Self::File)
|
Ok(Self::File)
|
||||||
|
} else if content_disposition.has_form_field("oneshot") {
|
||||||
|
Ok(Self::Oneshot)
|
||||||
} else if content_disposition.has_form_field("url") {
|
} else if content_disposition.has_form_field("url") {
|
||||||
Ok(Self::Url)
|
Ok(Self::Url)
|
||||||
} else {
|
} else {
|
||||||
|
@ -34,13 +40,25 @@ impl PasteType {
|
||||||
pub fn get_dir(&self) -> String {
|
pub fn get_dir(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::File => String::new(),
|
Self::File => String::new(),
|
||||||
|
Self::Oneshot => String::from("oneshot"),
|
||||||
Self::Url => String::from("url"),
|
Self::Url => String::from("url"),
|
||||||
|
Self::Trash => String::from("trash"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the given path with [`directory`](Self::get_dir) adjoined.
|
/// Returns the given path with [`directory`](Self::get_dir) adjoined.
|
||||||
pub fn get_path(&self, path: &Path) -> PathBuf {
|
pub fn get_path(&self, path: &Path) -> PathBuf {
|
||||||
path.join(self.get_dir())
|
let dir = self.get_dir();
|
||||||
|
if dir.is_empty() {
|
||||||
|
path.to_path_buf()
|
||||||
|
} else {
|
||||||
|
path.join(dir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the variant is [`Oneshot`](Self::Oneshot).
|
||||||
|
pub fn is_oneshot(&self) -> bool {
|
||||||
|
self == &Self::Oneshot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +101,10 @@ impl Paste {
|
||||||
Some(v) => v.to_string(),
|
Some(v) => v.to_string(),
|
||||||
None => String::from("file"),
|
None => String::from("file"),
|
||||||
};
|
};
|
||||||
let mut path = config.server.upload_path.join(file_name);
|
let mut path = self
|
||||||
|
.type_
|
||||||
|
.get_path(&config.server.upload_path)
|
||||||
|
.join(file_name);
|
||||||
match path.clone().extension() {
|
match path.clone().extension() {
|
||||||
Some(extension) => {
|
Some(extension) => {
|
||||||
if let Some(file_name) = config.paste.random_url.generate() {
|
if let Some(file_name) = config.paste.random_url.generate() {
|
||||||
|
@ -189,17 +210,22 @@ mod tests {
|
||||||
);
|
);
|
||||||
fs::remove_file(file_name)?;
|
fs::remove_file(file_name)?;
|
||||||
|
|
||||||
|
for paste_type in &[PasteType::Url, PasteType::Oneshot] {
|
||||||
|
fs::create_dir_all(paste_type.get_path(&config.server.upload_path))?;
|
||||||
|
}
|
||||||
|
|
||||||
config.paste.random_url.enabled = false;
|
config.paste.random_url.enabled = false;
|
||||||
let paste = Paste {
|
let paste = Paste {
|
||||||
data: vec![116, 101, 115, 116],
|
data: vec![116, 101, 115, 116],
|
||||||
type_: PasteType::File,
|
type_: PasteType::Oneshot,
|
||||||
};
|
};
|
||||||
let file_name = paste.store_file("test.file", &config)?;
|
let file_name = paste.store_file("test.file", &config)?;
|
||||||
|
let file_path = PasteType::Oneshot
|
||||||
|
.get_path(&config.server.upload_path)
|
||||||
|
.join(&file_name);
|
||||||
assert_eq!("test.file", &file_name);
|
assert_eq!("test.file", &file_name);
|
||||||
assert_eq!("test", fs::read_to_string(&file_name)?);
|
assert_eq!("test", fs::read_to_string(&file_path)?);
|
||||||
fs::remove_file(file_name)?;
|
fs::remove_file(file_path)?;
|
||||||
|
|
||||||
fs::create_dir_all(PasteType::Url.get_path(&config.server.upload_path))?;
|
|
||||||
|
|
||||||
config.paste.random_url.enabled = true;
|
config.paste.random_url.enabled = true;
|
||||||
let url = String::from("https://orhun.dev/");
|
let url = String::from("https://orhun.dev/");
|
||||||
|
@ -221,7 +247,9 @@ mod tests {
|
||||||
};
|
};
|
||||||
assert!(paste.store_url(&config).is_err());
|
assert!(paste.store_url(&config).is_err());
|
||||||
|
|
||||||
fs::remove_dir(PasteType::Url.get_path(&config.server.upload_path))?;
|
for paste_type in &[PasteType::Url, PasteType::Oneshot] {
|
||||||
|
fs::remove_dir(paste_type.get_path(&config.server.upload_path))?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,27 +29,42 @@ async fn serve(
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let mut path = config.server.upload_path.join(&*file);
|
let mut path = config.server.upload_path.join(&*file);
|
||||||
let mut paste_type = PasteType::File;
|
let mut paste_type = PasteType::File;
|
||||||
for type_ in &[PasteType::Url] {
|
if !path.exists() || path.is_dir() {
|
||||||
if !path.exists()
|
for type_ in &[PasteType::Url, PasteType::Oneshot] {
|
||||||
|| path.file_name().map(|v| v.to_str()).flatten() == Some(&type_.get_dir())
|
let alt_path = type_.get_path(&config.server.upload_path).join(&*file);
|
||||||
{
|
if alt_path.exists()
|
||||||
path = config.server.upload_path.join(type_.get_dir()).join(&*file);
|
|| path.file_name().map(|v| v.to_str()).flatten() == Some(&type_.get_dir())
|
||||||
paste_type = *type_;
|
{
|
||||||
break;
|
path = alt_path;
|
||||||
|
paste_type = *type_;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match paste_type {
|
match paste_type {
|
||||||
PasteType::File => Ok(NamedFile::open(&path)?
|
PasteType::File | PasteType::Oneshot => {
|
||||||
.disable_content_disposition()
|
let response = NamedFile::open(&path)?
|
||||||
.set_content_type(
|
.disable_content_disposition()
|
||||||
mime::get_mime_type(&config.paste.mime_override, file.to_string())
|
.set_content_type(
|
||||||
.map_err(error::ErrorInternalServerError)?,
|
mime::get_mime_type(&config.paste.mime_override, file.to_string())
|
||||||
)
|
.map_err(error::ErrorInternalServerError)?,
|
||||||
.prefer_utf8(true)
|
)
|
||||||
.into_response(&request)?),
|
.prefer_utf8(true)
|
||||||
|
.into_response(&request)?;
|
||||||
|
if paste_type.is_oneshot() {
|
||||||
|
fs::rename(
|
||||||
|
path,
|
||||||
|
PasteType::Trash
|
||||||
|
.get_path(&config.server.upload_path)
|
||||||
|
.join(&*file),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
PasteType::Url => Ok(HttpResponse::Found()
|
PasteType::Url => Ok(HttpResponse::Found()
|
||||||
.header("Location", fs::read_to_string(&path)?)
|
.header("Location", fs::read_to_string(&path)?)
|
||||||
.finish()),
|
.finish()),
|
||||||
|
PasteType::Trash => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,8 +101,11 @@ async fn upload(
|
||||||
type_: paste_type,
|
type_: paste_type,
|
||||||
};
|
};
|
||||||
let file_name = match paste_type {
|
let file_name = match paste_type {
|
||||||
PasteType::File => paste.store_file(content.get_file_name()?, &config)?,
|
PasteType::File | PasteType::Oneshot => {
|
||||||
|
paste.store_file(content.get_file_name()?, &config)?
|
||||||
|
}
|
||||||
PasteType::Url => paste.store_url(&config)?,
|
PasteType::Url => paste.store_url(&config)?,
|
||||||
|
PasteType::Trash => unreachable!(),
|
||||||
};
|
};
|
||||||
log::info!("{} ({}) is uploaded from {}", file_name, bytes_unit, host);
|
log::info!("{} ({}) is uploaded from {}", file_name, bytes_unit, host);
|
||||||
urls.push(format!(
|
urls.push(format!(
|
||||||
|
|
Loading…
Reference in a new issue