Skip to content

Commit 14a2655

Browse files
committed
feat: owner cookie
1 parent 4ac2e9a commit 14a2655

File tree

9 files changed

+312
-51
lines changed

9 files changed

+312
-51
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ thiserror = "1.0.31"
2424
tokio = { version = "1.18.1", features = ["full"] }
2525
url = { version = "2.2.2", features = ["serde"] }
2626
mime_guess = "2.0.4"
27-
serde_with = "1.13.0"
27+
serde_with = { version = "1.13.0", features = ["chrono"] }
2828
syntect = "5.0.0"
2929
askama = { version = "0.11.1", features = ["with-actix-web"] }
3030
askama_actix = "0.13.0"
31+
chrono = { version = "0.4.19", features = ["serde"] }
32+
actix-utils = "3.0.0"
3133

3234
[dependencies.figment]
3335
version = "0.10.6"

src/config.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
use std::path::Path;
22

33
use anyhow::{Context, Result};
4+
use chrono::Duration;
45
use figment::{
56
providers::{Env, Format, Toml},
67
Figment,
78
};
89
use serde::Deserialize;
10+
use serde_with::{serde_as, DurationSeconds};
911

12+
#[serde_as]
1013
#[derive(Deserialize)]
1114
pub struct Config {
12-
pub max_age: f64,
13-
pub time_to_delete: f64,
15+
#[serde_as(as = "DurationSeconds<i64>")]
16+
pub max_age: Duration,
17+
#[serde_as(as = "DurationSeconds<i64>")]
18+
pub time_to_delete: Duration,
1419
}
1520

1621
impl Config {

src/db.rs

Lines changed: 78 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,48 @@
1-
use crate::{util::ReadableAlphanumeric, StorageConfiguration, RESERVED_URLS};
21
use bonsaidb::{
3-
core::schema,
2+
core::schema::{self, Qualified},
43
local::{config::Builder, AsyncDatabase},
54
};
65
use bonsaidb_files::{
7-
direct::{Async, File},
8-
BonsaiFiles, FileConfig, FilesSchema, Truncate,
6+
direct::{self, Async},
7+
FileConfig, FilesSchema, Truncate,
98
};
9+
use chrono::{Duration, Utc};
1010
use rand::distributions::DistString;
11+
use serde::{Deserialize, Serialize};
12+
13+
use crate::{util::ReadableAlphanumeric, StorageConfiguration, RESERVED_URLS};
14+
15+
type Result<T = ()> = std::result::Result<T, bonsaidb::core::Error>;
16+
pub type DateTime = chrono::DateTime<Utc>;
17+
18+
#[derive(Serialize, Deserialize, Debug, Clone)]
19+
pub struct Metadata {
20+
pub delete_at: Option<DateTime>,
21+
pub owner: String,
22+
}
1123

12-
type Result<T> = std::result::Result<T, bonsaidb::core::Error>;
13-
type FileResult<T> = std::result::Result<T, bonsaidb_files::Error>;
24+
pub struct Files;
25+
impl FileConfig for Files {
26+
type Metadata = Metadata;
27+
28+
const BLOCK_SIZE: usize = 65_536;
29+
30+
fn files_name() -> schema::CollectionName {
31+
Qualified::private("files")
32+
}
33+
34+
fn blocks_name() -> schema::CollectionName {
35+
Qualified::private("blocks")
36+
}
37+
}
38+
39+
type File = direct::File<Async<AsyncDatabase>, Files>;
1440

1541
#[derive(Debug, schema::Schema)]
16-
#[schema(name = "paste", include=[FilesSchema<BonsaiFiles>])]
42+
#[schema(name = "paste", include=[FilesSchema<Files>])]
1743
struct Schema;
1844

19-
pub struct DB(pub AsyncDatabase);
45+
pub struct DB(AsyncDatabase);
2046

2147
impl DB {
2248
pub async fn new() -> Result<Self> {
@@ -25,37 +51,72 @@ impl DB {
2551
))
2652
}
2753

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
54+
pub async fn delete_at(&self, name: &str, delete_at: DateTime) -> Result {
55+
if let Some(mut file) = Files::load_async(name, &self.0).await? {
56+
let metadata = file.metadata().expect("all files have metadata").clone();
57+
file.update_metadata(Metadata {
58+
delete_at: Some(delete_at),
59+
..metadata
60+
})
61+
.await?;
62+
}
63+
Ok(())
64+
}
65+
66+
pub async fn file_owner(&self, name: &str) -> Result<Option<String>> {
67+
Ok(Files::load_async(name, &self.0)
68+
.await?
69+
.map(|m| m.metadata().expect("all files have metadata").owner.clone()))
70+
}
71+
72+
pub async fn load_file(&self, name: &str) -> Result<Option<File>> {
73+
if let Some(file) = Files::load_async(name, &self.0).await? {
74+
if let Some(delete_at) = file.metadata().and_then(|m| m.delete_at) {
75+
if Utc::now() > delete_at {
76+
file.delete().await?;
77+
return Ok(None);
78+
}
79+
}
80+
Ok(Some(file))
81+
} else {
82+
Ok(None)
83+
}
3184
}
3285

33-
pub async fn new_file(&self) -> FileResult<File<Async<AsyncDatabase>>> {
86+
pub async fn new_file(&self, owner: String, ttl: Option<Duration>) -> Result<File> {
3487
let mut tries = 0;
3588
// TODO auto increase
3689
let length = 4;
37-
Ok(loop {
90+
let mut file = loop {
3891
let name = loop {
3992
let id = ReadableAlphanumeric.sample_string(&mut rand::thread_rng(), length);
4093
if !RESERVED_URLS.contains(&id.as_str()) {
4194
break id;
4295
}
4396
};
4497
tries += 1;
45-
match BonsaiFiles::build(&name).create_async(&self.0).await {
98+
match Files::build(&name).create_async(&self.0).await {
4699
Ok(file) => break file,
47100
Err(bonsaidb_files::Error::Database(
48101
bonsaidb::core::Error::UniqueKeyViolation { .. },
49102
)) if tries > 5 => {
50-
let file = BonsaiFiles::load_or_create_async(&name, true, &self.0).await?;
103+
let file = Files::load_or_create_async(&name, true, &self.0).await?;
51104
file.truncate(0, Truncate::RemovingStart).await?;
52105
break file;
53106
}
54107
Err(bonsaidb_files::Error::Database(
55108
bonsaidb::core::Error::UniqueKeyViolation { .. },
56109
)) => continue,
57-
Err(err) => return Err(err),
110+
Err(err) => return Err(err.into()),
58111
}
59-
})
112+
};
113+
114+
file.update_metadata(Some(Metadata {
115+
delete_at: ttl.map(|ttl| Utc::now() + ttl),
116+
owner,
117+
}))
118+
.await?;
119+
120+
Ok(file)
60121
}
61122
}

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ async fn main() -> Result<()> {
2626
.unwrap_or_else(|| PathBuf::from("config.toml"));
2727

2828
info!(
29-
"Loading config from `{}`, this can be changed by the env variable `FRONTEND_CONFIG`",
29+
"Loading config from `{}`, this can be changed by the env variable `PASTEMP_CONFIG`",
3030
config_path.display()
3131
);
3232
if !config_path.is_file() {

0 commit comments

Comments
 (0)