Skip to content

Commit 4ac2e9a

Browse files
committed
visual update
1 parent b4a94b1 commit 4ac2e9a

17 files changed

+820
-575
lines changed

Cargo.lock

Lines changed: 95 additions & 75 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,24 @@ edition = "2021"
88
actix-multipart = "0.4.0"
99
actix-web = "4.0.1"
1010
actix-web-codegen = { git = "https://github.com/ModProg/actix-web", branch = "advanced_route_macro" }
11-
actix-web-lab = "0.15.0"
12-
anyhow = "1.0.56"
11+
actix-web-lab = "0.16.1"
12+
anyhow = "1.0.57"
1313
async-trait = "0.1.53"
1414
bonsaidb = { git = "https://github.com/khonsulabs/bonsaidb", features = ["local-full"] }
1515
bonsaidb-files = { git = "https://github.com/khonsulabs/bonsaidb", features = ["async"] }
1616
derive_more = "0.99.17"
17-
1817
env_logger = "0.9.0"
1918
futures = "0.3.21"
2019
futures-util = "0.3.21"
21-
log = "0.4.16"
20+
log = "0.4.17"
2221
rand = "0.8.5"
23-
serde = "1.0.136"
24-
thiserror = "1.0.30"
25-
tokio = { version = "1.17.0", features = ["full"] }
22+
serde = "1.0.137"
23+
thiserror = "1.0.31"
24+
tokio = { version = "1.18.1", features = ["full"] }
2625
url = { version = "2.2.2", features = ["serde"] }
2726
mime_guess = "2.0.4"
2827
serde_with = "1.13.0"
29-
syntect = "4.6.0"
28+
syntect = "5.0.0"
3029
askama = { version = "0.11.1", features = ["with-actix-web"] }
3130
askama_actix = "0.13.0"
3231

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22

33
## Simple API
44
### Retrieve Data
5-
The server will based on the user agent decide whether to send the data as a raw file.
5+
The server decides based on the UserAgent whether to send the data as a raw file or embeded in a website. To differentiated browsers from non browsers it uses the `Mozilla` all modern browsers (even IE) send.
66

7-
As for some reason all browsers send `Mozilla` this is going to be used for now.
7+
For a browser this will return a HTML with the file embeded and displayed correctly with added controls for e.g. deleting the entry. For all other requests (mainly tools like curl) the file will be returned as raw data.
88

9-
For a browser this will return a HTML with the file embeded with added controlls for e.g. delete the entry. For all other requests (mainly things like curl) the file will be returned as raw data.
10-
11-
- get("/:id") -> return entry as text
12-
- get("/:id.bin") -> return entry as binary
13-
- get("/:id.bin?mime={mime}") -> return entry as binary, set mime type to `mime`
14-
- get("/:id.:ext") -> return entry as the expect type for the extension
9+
- get("/:id") -> return entry as text
10+
- get("/:id.:ext") -> return entry as the expect type for the extension
11+
- for code files this will return highlighted code (as long as it is supported by [syntect](https://github.com/trishume/syntect))
12+
- for image files it will embed the file in an `<img>` tag to display.
1513

1614
### Delete entry
17-
There is the semantically correct way of deleting data using delete requests, but to make the website work without JS because there are people like that, it also supports using ?delete with a get request.
15+
There is the semantically correct way of deleting data using delete requests, but to make the website work without JS, it also supports using a get endpoint for deletion. The extension is optional and will be ignored.
16+
17+
Deleting a file can either be done by the original uploader, identified via a cookie or a random passphrase imidiatly, as well as anyone viewing it with a 30 minute delay.
1818

19-
- delete("/:id")
20-
- get("/:id/delete")
19+
- delete("/:id<.:ext>")
20+
- get("delete/:id<.:ext>")
2121

2222
### Add entry
2323
There are multiple ways of to add entries.

config.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
max_age = 172800
2+
time_to_delete = 1800
13
base_url = "http://localhost:8000"

src/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ use figment::{
66
Figment,
77
};
88
use serde::Deserialize;
9-
use url::Url;
109

1110
#[derive(Deserialize)]
1211
pub struct Config {
13-
pub base_url: Url,
12+
pub max_age: f64,
13+
pub time_to_delete: f64,
1414
}
1515

1616
impl Config {

src/db.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use crate::{util::ReadableAlphanumeric, StorageConfiguration, RESERVED_URLS};
2+
use bonsaidb::{
3+
core::schema,
4+
local::{config::Builder, AsyncDatabase},
5+
};
6+
use bonsaidb_files::{
7+
direct::{Async, File},
8+
BonsaiFiles, FileConfig, FilesSchema, Truncate,
9+
};
10+
use rand::distributions::DistString;
11+
12+
type Result<T> = std::result::Result<T, bonsaidb::core::Error>;
13+
type FileResult<T> = std::result::Result<T, bonsaidb_files::Error>;
14+
15+
#[derive(Debug, schema::Schema)]
16+
#[schema(name = "paste", include=[FilesSchema<BonsaiFiles>])]
17+
struct Schema;
18+
19+
pub struct DB(pub AsyncDatabase);
20+
21+
impl DB {
22+
pub async fn new() -> Result<Self> {
23+
Ok(Self(
24+
AsyncDatabase::open::<Schema>(StorageConfiguration::new("data.bonsaidb")).await?,
25+
))
26+
}
27+
28+
pub async fn load_file(&self, name: &str) -> FileResult<Option<File<Async<AsyncDatabase>>>> {
29+
// TODO delete file if marked for deletion
30+
BonsaiFiles::load_async(name, &self.0).await
31+
}
32+
33+
pub async fn new_file(&self) -> FileResult<File<Async<AsyncDatabase>>> {
34+
let mut tries = 0;
35+
// TODO auto increase
36+
let length = 4;
37+
Ok(loop {
38+
let name = loop {
39+
let id = ReadableAlphanumeric.sample_string(&mut rand::thread_rng(), length);
40+
if !RESERVED_URLS.contains(&id.as_str()) {
41+
break id;
42+
}
43+
};
44+
tries += 1;
45+
match BonsaiFiles::build(&name).create_async(&self.0).await {
46+
Ok(file) => break file,
47+
Err(bonsaidb_files::Error::Database(
48+
bonsaidb::core::Error::UniqueKeyViolation { .. },
49+
)) if tries > 5 => {
50+
let file = BonsaiFiles::load_or_create_async(&name, true, &self.0).await?;
51+
file.truncate(0, Truncate::RemovingStart).await?;
52+
break file;
53+
}
54+
Err(bonsaidb_files::Error::Database(
55+
bonsaidb::core::Error::UniqueKeyViolation { .. },
56+
)) => continue,
57+
Err(err) => return Err(err),
58+
}
59+
})
60+
}
61+
}

src/main.rs

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,20 @@ use std::{env, path::PathBuf};
22

33
use actix_web::{web::Data, App, HttpServer};
44
use anyhow::Result;
5-
use bonsaidb::{
6-
core::schema::{self, Collection},
7-
local::{
8-
config::{Builder, StorageConfiguration},
9-
AsyncDatabase,
10-
},
11-
};
12-
use bonsaidb_files::{BonsaiFiles, FilesSchema};
5+
use bonsaidb::local::config::StorageConfiguration;
136
use log::{error, info};
14-
use serde::{Deserialize, Serialize};
157
use syntect::parsing::SyntaxSet;
168

17-
use crate::config::Config;
9+
use config::Config;
10+
use db::DB;
1811

1912
mod config;
13+
mod db;
2014
mod simple;
2115
mod util;
2216

23-
#[derive(Debug, schema::Schema)]
24-
#[schema(name = "paste", include=[FilesSchema<BonsaiFiles>])]
25-
struct Schema;
2617

27-
#[derive(Deserialize, Serialize, Collection, Debug, Clone)]
28-
#[collection(name = "entries")]
29-
struct ActiveEntries {
30-
name: String,
31-
}
18+
pub const RESERVED_URLS: &[&str] = &["raw", "download", "delete"];
3219

3320
#[tokio::main]
3421
async fn main() -> Result<()> {
@@ -48,8 +35,7 @@ async fn main() -> Result<()> {
4835

4936
let config = Config::load(&config_path)?;
5037

51-
let database =
52-
Data::new(AsyncDatabase::open::<Schema>(StorageConfiguration::new("data.bonsaidb")).await?);
38+
let database = Data::new(DB::new().await?);
5339
let config = Data::new(config);
5440
let syntaxes = Data::new(SyntaxSet::load_defaults_newlines());
5541

0 commit comments

Comments
 (0)