use crate::{async_trait, GemBytes};
use std::{fs::File, io::Read};
pub enum Fluff {
File(String),
Input(String),
InputSensitive(String),
NotFound(String),
RedirectTemporary(String),
RedirectPermanent(String),
RedirectQueries {
path: String,
queries: Vec<(String, String)>,
},
RedirectQuery {
path: String,
query: String,
},
FailureTemporary(String),
FailurePermanent(String),
GoUp,
Lang {
lang: String,
body: String,
},
Document {
mime: String,
body: String,
},
Text(String),
DebugWait,
}
#[async_trait]
impl GemBytes for Fluff {
async fn gem_bytes(self) -> Vec<u8> {
match self {
Fluff::File(path) => {
let path = format!("static/{}", sanitize_filename::sanitize(path));
let Ok(mut file) = File::open(&path) else {
return "51 File not found.\r\n".into();
};
let mimetype = match mime_guess::from_path(path).first() {
Some(m) => m,
None => return "50 File mimetype could not be guessed.\r\n".into(),
};
let mut v: Vec<u8> = Vec::new();
match file.read_to_end(&mut v) {
Ok(_) => {
let mut v2 = format!("20 {mimetype}\r\n").into_bytes();
v2.append(&mut v);
v2
}
Err(e) => {
trace!("File read error: {e}");
"50 File read error.\r\n".into()
}
}
}
Fluff::NotFound(s) => format!("51 {s}\r\n").into(),
Fluff::Input(s) => format!("10 {s}\r\n").into(),
Fluff::InputSensitive(s) => format!("11 {s}\r\n").into(),
Fluff::RedirectTemporary(path) => format!("30 {path}\r\n").into(),
Fluff::RedirectPermanent(path) => format!("31 {path}\r\n").into(),
Fluff::RedirectQueries { path, queries } => {
if let Ok(url) = url::Url::parse_with_params("https://example.com", queries) {
format!(
"30 {path}?{}\r\n",
url.query().unwrap_or("").replace('+', "%20")
)
} else {
format!("30 {path}\r\n")
}
.into()
}
Fluff::RedirectQuery { path, query } => {
format!("30 {path}?{}\r\n", urlencoding::encode(&query)).into()
}
Fluff::FailureTemporary(s) => format!("40 {s}\r\n").into(),
Fluff::FailurePermanent(s) => format!("50 {s}\r\n").into(),
Fluff::GoUp => "30 ..\r\n".into(),
Fluff::Lang { lang, body } => format!("20 text/gemini; lang={lang}\r\n{body}").into(),
Fluff::Document { mime, body } => format!("20 {mime}\r\n{body}").into(),
Fluff::Text(s) => format!("20 text/gemini\r\n{s}").into(),
Fluff::DebugWait => {
std::thread::sleep(std::time::Duration::from_secs(10));
"20 text/gemini\r\n๐งต Waited 10 seconds!\n".into()
}
}
}
}