forked from Maurice/pastabble
Added URL shortener
This commit is contained in:
parent
1d32fb0365
commit
e874e4e473
@ -5,6 +5,8 @@ Welcome at PASTABBLE!
|
|||||||
## About
|
## About
|
||||||
Pastable is a lightweight and fast pastebin alternative and URL-shortener made by Plabble and written in Rust.
|
Pastable is a lightweight and fast pastebin alternative and URL-shortener made by Plabble and written in Rust.
|
||||||
|
|
||||||
|
For usage, see `about.html`
|
||||||
|
|
||||||
## Environment variables
|
## Environment variables
|
||||||
| Variable | Default |
|
| Variable | Default |
|
||||||
| -------- | ------- |
|
| -------- | ------- |
|
||||||
|
13
about.html
13
about.html
@ -17,12 +17,19 @@
|
|||||||
Get /: Show this page
|
Get /: Show this page
|
||||||
Get /{id}: Get paste by ID and return in plain text
|
Get /{id}: Get paste by ID and return in plain text
|
||||||
Post /: Create new paste (plain text raw body or form parameter 'content') and return random generated key
|
Post /: Create new paste (plain text raw body or form parameter 'content') and return random generated key
|
||||||
Post /{id}: Create new paste (plain text raw body) and return requested key if available, else random generated key
|
Post /{id}: Create new paste (plain text raw body) and return requested key if available, else random generated key
|
||||||
|
|
||||||
|
Get /to/{id}: Navigate to shortcut link (browser redirect)
|
||||||
|
Post /to: Create new link (plain text raw body or form parameter 'link') and return random generated key
|
||||||
|
Post /to/{id}: Create new link (plain text raw body) and return requested key if available, else random generated key
|
||||||
|
|
||||||
FROM TERMINAL
|
FROM TERMINAL
|
||||||
Pipe your input into: curl -F 'content=<-' paste.plabble.org -w "\n"
|
Pipe your input into: curl -F 'content=<-' paste.plabble.org -w '\n'
|
||||||
Or post it as raw data like: curl paste.plabble.org -H "Content-Type: text/plain" -d @- -w "\n"
|
Or post it as raw data like: curl paste.plabble.org -H 'Content-Type: text/plain' -d @- -w '\n'
|
||||||
You can create an alias for this! To get the result: curl paste.plabble.org/YOURID
|
You can create an alias for this! To get the result: curl paste.plabble.org/YOURID
|
||||||
|
|
||||||
|
For links:
|
||||||
|
Pipe your input into: curl -F 'link=<-' paste.plabble.org/to -w '\n'
|
||||||
</pre>
|
</pre>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
135
src/main.rs
135
src/main.rs
@ -1,15 +1,15 @@
|
|||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use kv::{Config, Store, Json};
|
use kv::{Config, Store, Json, Bucket, Value};
|
||||||
use paste::Paste;
|
use paste::Paste;
|
||||||
use rand::{Rng, distributions::Alphanumeric};
|
use rand::{Rng, distributions::Alphanumeric};
|
||||||
use rouille::{Response, router, try_or_400, post_input};
|
use rouille::{Response, router, try_or_400, post_input, Request};
|
||||||
|
|
||||||
mod paste;
|
mod paste;
|
||||||
|
|
||||||
// Generate random key function
|
// Generate random key function
|
||||||
fn new_key() -> String {
|
fn random_string() -> String {
|
||||||
rand::thread_rng()
|
rand::thread_rng()
|
||||||
.sample_iter(&Alphanumeric)
|
.sample_iter(&Alphanumeric)
|
||||||
.take(5)
|
.take(5)
|
||||||
@ -17,6 +17,18 @@ fn new_key() -> String {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate key using provided key or generate new one
|
||||||
|
fn generate_key<T : Value>(key: Option<String>, store: &Bucket<String, T>) -> String {
|
||||||
|
let mut new_key = key.unwrap_or(random_string());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if !store.contains(&new_key).unwrap() {
|
||||||
|
break new_key;
|
||||||
|
}
|
||||||
|
new_key = random_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Get settings
|
// Get settings
|
||||||
let port: u16 = env::var("PORT").unwrap_or(String::from("8080")).parse().expect("Failed to parse PORT variable");
|
let port: u16 = env::var("PORT").unwrap_or(String::from("8080")).parse().expect("Failed to parse PORT variable");
|
||||||
@ -26,9 +38,13 @@ fn main() {
|
|||||||
let store = Store::new(config).expect("Failed to initialize database store");
|
let store = Store::new(config).expect("Failed to initialize database store");
|
||||||
let about = fs::read_to_string("./about.html").expect("about.html not found!!");
|
let about = fs::read_to_string("./about.html").expect("about.html not found!!");
|
||||||
|
|
||||||
// Get pastes bucket (default)
|
// Get pastes bucket
|
||||||
let pastes = store.bucket::<String, Json<Paste>>(Some("pastes"))
|
let pastes = store.bucket::<String, Json<Paste>>(Some("pastes"))
|
||||||
.expect("Failed to open default bucket");
|
.expect("Failed to open pastes bucket");
|
||||||
|
|
||||||
|
// Get links bucket
|
||||||
|
let links = store.bucket::<String, String>(Some("links"))
|
||||||
|
.expect("Failed to open links bucket");
|
||||||
|
|
||||||
// Start server
|
// Start server
|
||||||
println!("Started PASTABBLE server on port {}", port);
|
println!("Started PASTABBLE server on port {}", port);
|
||||||
@ -37,9 +53,22 @@ fn main() {
|
|||||||
(GET) (/) => {
|
(GET) (/) => {
|
||||||
Response::html(&about)
|
Response::html(&about)
|
||||||
},
|
},
|
||||||
|
(GET) (/to/{id: String}) => {
|
||||||
|
match links.get(&id).expect("Failed to access links DB") {
|
||||||
|
Some(lnk) => {
|
||||||
|
Response::redirect_301(lnk)
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
Response::text(format!("Redirect with ID '{}' not found", &id))
|
||||||
|
.with_status_code(404)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(POST) (/to/{id: String}) => { register_link(&links, req, Some(id)) },
|
||||||
|
(POST) (/to) => { register_link(&links, req, None) },
|
||||||
(GET) (/{id: String}) => {
|
(GET) (/{id: String}) => {
|
||||||
// Get note from database, if exists
|
// Get note from database, if exists
|
||||||
match pastes.get(&id).expect("Failed to access DB") {
|
match pastes.get(&id).expect("Failed to access pastes DB") {
|
||||||
Some(paste) => {
|
Some(paste) => {
|
||||||
Response::text(paste.0.content)
|
Response::text(paste.0.content)
|
||||||
},
|
},
|
||||||
@ -49,45 +78,65 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(POST) (/{id: String}) => {
|
(POST) (/{id: String}) => {
|
||||||
// Use provided key or generate new one
|
let id = if id.is_empty() { None } else { Some(id) };
|
||||||
let key = if !id.is_empty() && !pastes.contains(&id).unwrap() {
|
register_paste(&pastes, req, id)
|
||||||
id
|
|
||||||
} else {
|
|
||||||
loop {
|
|
||||||
let new_key = new_key();
|
|
||||||
if !pastes.contains(&new_key).expect("Could not access store") {
|
|
||||||
break new_key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Try read body from form data, and if not present from request body
|
|
||||||
let body = match post_input!(&req, {
|
|
||||||
content: String
|
|
||||||
}) {
|
|
||||||
Ok(f) => {
|
|
||||||
f.content
|
|
||||||
},
|
|
||||||
Err(_) => {
|
|
||||||
try_or_400!(rouille::input::plain_text_body(&req))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create and save new note
|
|
||||||
let paste = Json(Paste {
|
|
||||||
content: body,
|
|
||||||
expires: None,
|
|
||||||
language: None,
|
|
||||||
created: Utc::now()
|
|
||||||
});
|
|
||||||
|
|
||||||
pastes.set(&key, &paste).expect("Failed to save note");
|
|
||||||
|
|
||||||
// Return key
|
|
||||||
Response::text(key)
|
|
||||||
},
|
},
|
||||||
_ => Response::empty_404()
|
_ => Response::empty_404()
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register paste handler
|
||||||
|
fn register_paste(pastes: &Bucket<String, Json<Paste>>, req: &Request, id: Option<String>) -> Response {
|
||||||
|
|
||||||
|
// Try read body from form data, and if not present from request body
|
||||||
|
let body = match post_input!(req, {
|
||||||
|
content: String
|
||||||
|
}) {
|
||||||
|
Ok(f) => {
|
||||||
|
f.content
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
try_or_400!(rouille::input::plain_text_body(req))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create and save new note
|
||||||
|
let paste = Json(Paste {
|
||||||
|
content: body,
|
||||||
|
expires: None,
|
||||||
|
language: None,
|
||||||
|
created: Utc::now()
|
||||||
|
});
|
||||||
|
|
||||||
|
let key = generate_key(id, &pastes);
|
||||||
|
pastes.set(&key, &paste).expect("Failed to save note");
|
||||||
|
pastes.flush().expect("Failed to svae paste to database");
|
||||||
|
|
||||||
|
// Return key
|
||||||
|
Response::text(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register link route handler
|
||||||
|
fn register_link(links: &Bucket<String,String>, req: &Request, id: Option<String>) -> Response {
|
||||||
|
|
||||||
|
// Try read body from form data, and if not present from request body
|
||||||
|
let link = match post_input!(req, {
|
||||||
|
link: String
|
||||||
|
}) {
|
||||||
|
Ok(f) => {
|
||||||
|
f.link
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
try_or_400!(rouille::input::plain_text_body(req))
|
||||||
|
}
|
||||||
|
}.trim().to_string();
|
||||||
|
|
||||||
|
let key = generate_key(id, &links);
|
||||||
|
links.set(&key, &link).expect("Failed to save link");
|
||||||
|
links.flush().expect("Failed to save link to database");
|
||||||
|
|
||||||
|
// Return key
|
||||||
|
Response::text(key)
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user