- added new pasta type URL and automatic redirection endpoint
- added water.css styling - added CL argument to set port - added raw URL to pasta list
This commit is contained in:
parent
e8b0e3a482
commit
f56ffa98e4
9 changed files with 251 additions and 120 deletions
229
src/main.rs
229
src/main.rs
|
@ -1,23 +1,32 @@
|
|||
extern crate core;
|
||||
|
||||
use actix_files as fs;
|
||||
use actix_web::web::Data;
|
||||
use actix_web::{get, post, web, App, HttpRequest, HttpResponse, HttpServer, Responder, Result};
|
||||
use askama::Template;
|
||||
use clap::Parser;
|
||||
use linkify::{LinkFinder, LinkKind};
|
||||
use rand::Rng;
|
||||
use regex::Regex;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Mutex;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use actix_files::NamedFile;
|
||||
use actix_web::{App, get, HttpRequest, HttpResponse, HttpServer, post, Responder, Result, web};
|
||||
use actix_web::web::Data;
|
||||
use askama::Template;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::animalnumbers::{to_animal_names, to_u64};
|
||||
use crate::pasta::{Pasta, PastaFormData};
|
||||
|
||||
mod pasta;
|
||||
mod animalnumbers;
|
||||
mod pasta;
|
||||
|
||||
struct AppState {
|
||||
pastas: Mutex<Vec<Pasta>>,
|
||||
pastas: Mutex<Vec<Pasta>>,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
#[clap(short, long, default_value_t = 8080)]
|
||||
port: u32,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
|
@ -27,130 +36,192 @@ struct IndexTemplate {}
|
|||
#[derive(Template)]
|
||||
#[template(path = "pasta.html")]
|
||||
struct PastaTemplate<'a> {
|
||||
pasta: &'a Pasta,
|
||||
pasta: &'a Pasta,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "pastalist.html")]
|
||||
struct PastaListTemplate<'a> {
|
||||
pastas: &'a Vec<Pasta>,
|
||||
pastas: &'a Vec<Pasta>,
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
async fn index() -> impl Responder {
|
||||
HttpResponse::Found().content_type("text/html").body(IndexTemplate {}.render().unwrap())
|
||||
HttpResponse::Found()
|
||||
.content_type("text/html")
|
||||
.body(IndexTemplate {}.render().unwrap())
|
||||
}
|
||||
|
||||
#[post("/create")]
|
||||
async fn create(data: web::Data<AppState>, pasta: web::Form<PastaFormData>) -> impl Responder {
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
|
||||
let mut innerPasta = pasta.into_inner();
|
||||
let inner_pasta = pasta.into_inner();
|
||||
|
||||
let timenow: i64 = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||
Ok(n) => n.as_secs(),
|
||||
Err(_) => panic!("SystemTime before UNIX EPOCH!"),
|
||||
} as i64;
|
||||
let timenow: i64 = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||
Ok(n) => n.as_secs(),
|
||||
Err(_) => panic!("SystemTime before UNIX EPOCH!"),
|
||||
} as i64;
|
||||
|
||||
let expiration = match innerPasta.expiration.as_str() {
|
||||
"1min" => timenow + 60,
|
||||
"10min" => timenow + 60 * 10,
|
||||
"1hour" => timenow + 60 * 60,
|
||||
"24hour" => timenow + 60 * 60 * 24,
|
||||
"1week" => timenow + 60 * 60 * 24 * 7,
|
||||
"never" => 0,
|
||||
_ => panic!("Unexpected expiration time!")
|
||||
};
|
||||
let expiration = match inner_pasta.expiration.as_str() {
|
||||
"1min" => timenow + 60,
|
||||
"10min" => timenow + 60 * 10,
|
||||
"1hour" => timenow + 60 * 60,
|
||||
"24hour" => timenow + 60 * 60 * 24,
|
||||
"1week" => timenow + 60 * 60 * 24 * 7,
|
||||
"never" => 0,
|
||||
_ => panic!("Unexpected expiration time!"),
|
||||
};
|
||||
|
||||
let mut newPasta = Pasta {
|
||||
id: rand::thread_rng().gen::<u16>() as u64,
|
||||
content: innerPasta.content,
|
||||
created: timenow,
|
||||
expiration,
|
||||
};
|
||||
let pasta_type = if is_valid_url(inner_pasta.content.as_str()) {
|
||||
String::from("url")
|
||||
} else {
|
||||
String::from("text")
|
||||
};
|
||||
|
||||
let id = newPasta.id;
|
||||
let new_pasta = Pasta {
|
||||
id: rand::thread_rng().gen::<u16>() as u64,
|
||||
content: inner_pasta.content,
|
||||
created: timenow,
|
||||
pasta_type,
|
||||
expiration,
|
||||
};
|
||||
|
||||
pastas.push(newPasta);
|
||||
let id = new_pasta.id;
|
||||
|
||||
HttpResponse::Found().append_header(("Location", format!("/pasta/{}", to_animal_names(id)))).finish()
|
||||
pastas.push(new_pasta);
|
||||
|
||||
HttpResponse::Found()
|
||||
.append_header(("Location", format!("/pasta/{}", to_animal_names(id))))
|
||||
.finish()
|
||||
}
|
||||
|
||||
#[get("/pasta/{id}")]
|
||||
async fn getpasta(data: web::Data<AppState>, id: web::Path<String>) -> HttpResponse {
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
let id = to_u64(&*id.into_inner());
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
let id = to_u64(&*id.into_inner());
|
||||
|
||||
remove_expired(&mut pastas);
|
||||
remove_expired(&mut pastas);
|
||||
|
||||
for pasta in pastas.iter() {
|
||||
if pasta.id == id {
|
||||
return HttpResponse::Found().content_type("text/html").body(PastaTemplate { pasta }.render().unwrap());
|
||||
}
|
||||
}
|
||||
for pasta in pastas.iter() {
|
||||
if pasta.id == id {
|
||||
return HttpResponse::Found()
|
||||
.content_type("text/html")
|
||||
.body(PastaTemplate { pasta }.render().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponse::Found().body("Pasta not found! :-(")
|
||||
HttpResponse::Found().body("Pasta not found! :-(")
|
||||
}
|
||||
|
||||
#[get("/rawpasta/{id}")]
|
||||
#[get("/url/{id}")]
|
||||
async fn redirecturl(data: web::Data<AppState>, id: web::Path<String>) -> HttpResponse {
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
let id = to_u64(&*id.into_inner());
|
||||
|
||||
remove_expired(&mut pastas);
|
||||
|
||||
for pasta in pastas.iter() {
|
||||
if pasta.id == id {
|
||||
if pasta.pasta_type == "url" {
|
||||
return HttpResponse::Found()
|
||||
.append_header(("Location", String::from(&pasta.content)))
|
||||
.finish();
|
||||
} else {
|
||||
return HttpResponse::Found().body("This is not a valid URL. :-(");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponse::Found().body("Pasta not found! :-(")
|
||||
}
|
||||
|
||||
#[get("/raw/{id}")]
|
||||
async fn getrawpasta(data: web::Data<AppState>, id: web::Path<String>) -> String {
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
let id = to_u64(&*id.into_inner());
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
let id = to_u64(&*id.into_inner());
|
||||
|
||||
remove_expired(&mut pastas);
|
||||
remove_expired(&mut pastas);
|
||||
|
||||
for pasta in pastas.iter() {
|
||||
if pasta.id == id {
|
||||
return pasta.content.to_owned();
|
||||
}
|
||||
}
|
||||
for pasta in pastas.iter() {
|
||||
if pasta.id == id {
|
||||
return pasta.content.to_owned();
|
||||
}
|
||||
}
|
||||
|
||||
String::from("Pasta not found! :-(")
|
||||
String::from("Pasta not found! :-(")
|
||||
}
|
||||
|
||||
#[get("/remove/{id}")]
|
||||
async fn remove(data: web::Data<AppState>, id: web::Path<String>) -> HttpResponse {
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
let id = to_u64(&*id.into_inner());
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
let id = to_u64(&*id.into_inner());
|
||||
|
||||
remove_expired(&mut pastas);
|
||||
remove_expired(&mut pastas);
|
||||
|
||||
for (i, pasta) in pastas.iter().enumerate() {
|
||||
if pasta.id == id {
|
||||
pastas.remove(i);
|
||||
return HttpResponse::Found().append_header(("Location", "/pastalist")).finish();
|
||||
}
|
||||
}
|
||||
for (i, pasta) in pastas.iter().enumerate() {
|
||||
if pasta.id == id {
|
||||
pastas.remove(i);
|
||||
return HttpResponse::Found()
|
||||
.append_header(("Location", "/pastalist"))
|
||||
.finish();
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponse::Found().body("Pasta not found! :-(")
|
||||
HttpResponse::Found().body("Pasta not found! :-(")
|
||||
}
|
||||
|
||||
#[get("/pastalist")]
|
||||
async fn list(data: web::Data<AppState>) -> HttpResponse {
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
|
||||
remove_expired(&mut pastas);
|
||||
remove_expired(&mut pastas);
|
||||
|
||||
HttpResponse::Found().content_type("text/html").body(PastaListTemplate { pastas: &pastas }.render().unwrap())
|
||||
HttpResponse::Found()
|
||||
.content_type("text/html")
|
||||
.body(PastaListTemplate { pastas: &pastas }.render().unwrap())
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let data = web::Data::new(AppState {
|
||||
pastas: Mutex::new(Vec::new()),
|
||||
});
|
||||
let args = Args::parse();
|
||||
println!(
|
||||
"{}",
|
||||
format!("Listening on http://127.0.0.1:{}", args.port.to_string())
|
||||
);
|
||||
|
||||
HttpServer::new(move || App::new().app_data(data.clone()).service(index).service(create).service(getpasta).service(getrawpasta).service(remove).service(list)
|
||||
).bind("127.0.0.1:8080")?.run().await
|
||||
let data = web::Data::new(AppState {
|
||||
pastas: Mutex::new(Vec::new()),
|
||||
});
|
||||
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.app_data(data.clone())
|
||||
.service(index)
|
||||
.service(create)
|
||||
.service(getpasta)
|
||||
.service(redirecturl)
|
||||
.service(getrawpasta)
|
||||
.service(remove)
|
||||
.service(list)
|
||||
.service(fs::Files::new("/static", "./static"))
|
||||
})
|
||||
.bind(format!("127.0.0.1:{}", args.port.to_string()))?
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
|
||||
fn remove_expired(pastas: &mut Vec<Pasta>) {
|
||||
let timenow: i64 = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||
Ok(n) => n.as_secs(),
|
||||
Err(_) => panic!("SystemTime before UNIX EPOCH!"),
|
||||
} as i64;
|
||||
let timenow: i64 = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||
Ok(n) => n.as_secs(),
|
||||
Err(_) => panic!("SystemTime before UNIX EPOCH!"),
|
||||
} as i64;
|
||||
|
||||
pastas.retain(|p| {
|
||||
p.expiration == 0 || p.expiration > timenow
|
||||
});
|
||||
pastas.retain(|p| p.expiration == 0 || p.expiration > timenow);
|
||||
}
|
||||
|
||||
fn is_valid_url(url: &str) -> bool {
|
||||
let finder = LinkFinder::new();
|
||||
let spans: Vec<_> = finder.spans(url).collect();
|
||||
spans[0].as_str() == url && Some(&LinkKind::Url) == spans[0].kind()
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@ pub struct Pasta {
|
|||
pub id: u64,
|
||||
pub content: String,
|
||||
pub created: i64,
|
||||
pub expiration: i64
|
||||
pub expiration: i64,
|
||||
pub pasta_type: String
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue