Initial commit
This commit is contained in:
commit
1d32fb0365
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
/data
|
1161
Cargo.lock
generated
Normal file
1161
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "pastabble"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
kv = { version = "0.24.0", features = ["json-value"] }
|
||||
serde = { version = "1.0.145", features = ["derive"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
rand = "0.8.5"
|
||||
rouille = "3.6.1"
|
7
Dockerfile
Normal file
7
Dockerfile
Normal file
@ -0,0 +1,7 @@
|
||||
FROM alpine:latest
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./target/x86_64-unknown-linux-musl/release/ /app
|
||||
COPY ./about.html /app/about.html
|
||||
|
||||
ENTRYPOINT [ "./pastabble" ]
|
21
README.md
Normal file
21
README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# PASTABBLE
|
||||
|
||||
Welcome at PASTABBLE!
|
||||
|
||||
## About
|
||||
Pastable is a lightweight and fast pastebin alternative and URL-shortener made by Plabble and written in Rust.
|
||||
|
||||
## Environment variables
|
||||
| Variable | Default |
|
||||
| -------- | ------- |
|
||||
| PORT | 8080 |
|
||||
| DATA_DIR | ./data |
|
||||
|
||||
## Setup
|
||||
Place the about.html file from this folder in the same folder as the binary
|
||||
|
||||
## Requirements
|
||||
Rust and musl toolchain should be installed
|
||||
```
|
||||
rustup target add x86_64-unknown-linux-musl
|
||||
```
|
28
about.html
Normal file
28
about.html
Normal file
@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>About</title>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
Welcome at PASTABBLE!
|
||||
|
||||
ABOUT
|
||||
Pastable is a lightweight and fast pastebin alternative, and URL-shortener made by Plabble and written in Rust.
|
||||
|
||||
USAGE
|
||||
Get /: Show this page
|
||||
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 /{id}: Create new paste (plain text raw body) and return requested key if available, else random generated key
|
||||
|
||||
FROM TERMINAL
|
||||
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"
|
||||
You can create an alias for this! To get the result: curl paste.plabble.org/YOURID
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
5
build.sh
Executable file
5
build.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
RUNNER="podman"
|
||||
|
||||
cargo build --target x86_64-unknown-linux-musl --release
|
||||
$RUNNER build -t pastabble:latest .
|
93
src/main.rs
Normal file
93
src/main.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use std::{env, fs};
|
||||
|
||||
use chrono::Utc;
|
||||
use kv::{Config, Store, Json};
|
||||
use paste::Paste;
|
||||
use rand::{Rng, distributions::Alphanumeric};
|
||||
use rouille::{Response, router, try_or_400, post_input};
|
||||
|
||||
mod paste;
|
||||
|
||||
// Generate random key function
|
||||
fn new_key() -> String {
|
||||
rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(5)
|
||||
.map(char::from)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Get settings
|
||||
let port: u16 = env::var("PORT").unwrap_or(String::from("8080")).parse().expect("Failed to parse PORT variable");
|
||||
let data_dir: String = env::var("DATA_DIR").unwrap_or(String::from("./data"));
|
||||
|
||||
let config = Config::new(data_dir);
|
||||
let store = Store::new(config).expect("Failed to initialize database store");
|
||||
let about = fs::read_to_string("./about.html").expect("about.html not found!!");
|
||||
|
||||
// Get pastes bucket (default)
|
||||
let pastes = store.bucket::<String, Json<Paste>>(Some("pastes"))
|
||||
.expect("Failed to open default bucket");
|
||||
|
||||
// Start server
|
||||
println!("Started PASTABBLE server on port {}", port);
|
||||
rouille::start_server(format!("0.0.0.0:{}", port), move |req| {
|
||||
router!(req,
|
||||
(GET) (/) => {
|
||||
Response::html(&about)
|
||||
},
|
||||
(GET) (/{id: String}) => {
|
||||
// Get note from database, if exists
|
||||
match pastes.get(&id).expect("Failed to access DB") {
|
||||
Some(paste) => {
|
||||
Response::text(paste.0.content)
|
||||
},
|
||||
None => {
|
||||
Response::text(format!("Note with ID '{}' not found", &id))
|
||||
.with_status_code(404)
|
||||
}
|
||||
}
|
||||
},
|
||||
(POST) (/{id: String}) => {
|
||||
// Use provided key or generate new one
|
||||
let key = if !id.is_empty() && !pastes.contains(&id).unwrap() {
|
||||
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()
|
||||
)
|
||||
});
|
||||
}
|
13
src/paste.rs
Normal file
13
src/paste.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use chrono::serde::ts_seconds_option;
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
pub struct Paste {
|
||||
pub content: String,
|
||||
pub language: Option<String>,
|
||||
|
||||
#[serde(with = "ts_seconds_option")]
|
||||
pub expires: Option<DateTime<Utc>>,
|
||||
pub created: DateTime<Utc>
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user