mirror of https://github.com/w4/bin.git
133 lines
3.1 KiB
Rust
133 lines
3.1 KiB
Rust
#![feature(proc_macro_hygiene, decl_macro)]
|
|
|
|
#[macro_use]
|
|
extern crate lazy_static;
|
|
|
|
#[macro_use]
|
|
extern crate rocket;
|
|
|
|
extern crate askama;
|
|
|
|
mod highlight;
|
|
mod io;
|
|
mod params;
|
|
|
|
use highlight::highlight;
|
|
use io::{generate_id, get_paste, store_paste};
|
|
use params::{HostHeader, IsPlaintextRequest};
|
|
|
|
use askama::{Html as AskamaHtml, MarkupDisplay, Template};
|
|
|
|
use rocket::http::{ContentType, RawStr, Status};
|
|
use rocket::request::Form;
|
|
use rocket::response::content::{Content, Html};
|
|
use rocket::response::Redirect;
|
|
use rocket::Data;
|
|
|
|
use std::borrow::Cow;
|
|
use std::io::Read;
|
|
|
|
use tokio::io::AsyncReadExt;
|
|
|
|
///
|
|
/// Homepage
|
|
///
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "index.html")]
|
|
struct Index;
|
|
|
|
#[get("/")]
|
|
fn index() -> Result<Html<String>, Status> {
|
|
Index
|
|
.render()
|
|
.map(Html)
|
|
.map_err(|_| Status::InternalServerError)
|
|
}
|
|
|
|
///
|
|
/// Submit Paste
|
|
///
|
|
|
|
#[derive(FromForm)]
|
|
struct IndexForm {
|
|
val: String,
|
|
}
|
|
|
|
#[post("/", data = "<input>")]
|
|
async fn submit(input: Form<IndexForm>) -> Redirect {
|
|
let id = generate_id();
|
|
let uri = uri!(show_paste: &id);
|
|
store_paste(id, input.into_inner().val).await;
|
|
Redirect::to(uri)
|
|
}
|
|
|
|
#[put("/", data = "<input>")]
|
|
async fn submit_raw(input: Data, host: HostHeader<'_>) -> Result<String, Status> {
|
|
let mut data = String::new();
|
|
input.open().take(1024 * 1000)
|
|
.read_to_string(&mut data).await
|
|
.map_err(|_| Status::InternalServerError)?;
|
|
|
|
let id = generate_id();
|
|
let uri = uri!(show_paste: &id);
|
|
|
|
store_paste(id, data).await;
|
|
|
|
match *host {
|
|
Some(host) => Ok(format!("https://{}{}", host, uri)),
|
|
None => Ok(format!("{}", uri)),
|
|
}
|
|
}
|
|
|
|
///
|
|
/// Show paste page
|
|
///
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "paste.html")]
|
|
struct ShowPaste<'a> {
|
|
content: MarkupDisplay<AskamaHtml, Cow<'a, String>>,
|
|
}
|
|
|
|
#[get("/<key>")]
|
|
async fn show_paste(key: String, plaintext: IsPlaintextRequest) -> Result<Content<String>, Status> {
|
|
let mut splitter = key.splitn(2, '.');
|
|
let key = splitter.next().ok_or_else(|| Status::NotFound)?;
|
|
let ext = splitter.next();
|
|
|
|
let entry = &*get_paste(key).await.ok_or_else(|| Status::NotFound)?;
|
|
|
|
if *plaintext {
|
|
Ok(Content(ContentType::Plain, entry.to_string()))
|
|
} else {
|
|
let code_highlighted = match ext {
|
|
Some(extension) => match highlight(&entry, extension) {
|
|
Some(html) => html,
|
|
None => return Err(Status::NotFound),
|
|
},
|
|
None => String::from(RawStr::from_str(entry).html_escape()),
|
|
};
|
|
|
|
// Add <code> tags to enable line numbering with CSS
|
|
let html = format!(
|
|
"<code>{}</code>",
|
|
code_highlighted.replace("\n", "</code><code>")
|
|
);
|
|
|
|
let content = MarkupDisplay::new_safe(Cow::Borrowed(&html), AskamaHtml);
|
|
|
|
let template = ShowPaste { content };
|
|
match template.render() {
|
|
Ok(html) => Ok(Content(ContentType::HTML, html)),
|
|
Err(_) => Err(Status::InternalServerError),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
rocket::ignite()
|
|
.mount("/", routes![index, submit, submit_raw, show_paste])
|
|
.launch();
|
|
}
|