1
- use crate :: { util:: ReadableAlphanumeric , StorageConfiguration , RESERVED_URLS } ;
2
1
use bonsaidb:: {
3
- core:: schema,
2
+ core:: schema:: { self , Qualified } ,
4
3
local:: { config:: Builder , AsyncDatabase } ,
5
4
} ;
6
5
use bonsaidb_files:: {
7
- direct:: { Async , File } ,
8
- BonsaiFiles , FileConfig , FilesSchema , Truncate ,
6
+ direct:: { self , Async } ,
7
+ FileConfig , FilesSchema , Truncate ,
9
8
} ;
9
+ use chrono:: { Duration , Utc } ;
10
10
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
+ }
11
23
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 > ;
14
40
15
41
#[ derive( Debug , schema:: Schema ) ]
16
- #[ schema( name = "paste" , include=[ FilesSchema <BonsaiFiles >] ) ]
42
+ #[ schema( name = "paste" , include=[ FilesSchema <Files >] ) ]
17
43
struct Schema ;
18
44
19
- pub struct DB ( pub AsyncDatabase ) ;
45
+ pub struct DB ( AsyncDatabase ) ;
20
46
21
47
impl DB {
22
48
pub async fn new ( ) -> Result < Self > {
@@ -25,37 +51,72 @@ impl DB {
25
51
) )
26
52
}
27
53
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
+ }
31
84
}
32
85
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 > {
34
87
let mut tries = 0 ;
35
88
// TODO auto increase
36
89
let length = 4 ;
37
- Ok ( loop {
90
+ let mut file = loop {
38
91
let name = loop {
39
92
let id = ReadableAlphanumeric . sample_string ( & mut rand:: thread_rng ( ) , length) ;
40
93
if !RESERVED_URLS . contains ( & id. as_str ( ) ) {
41
94
break id;
42
95
}
43
96
} ;
44
97
tries += 1 ;
45
- match BonsaiFiles :: build ( & name) . create_async ( & self . 0 ) . await {
98
+ match Files :: build ( & name) . create_async ( & self . 0 ) . await {
46
99
Ok ( file) => break file,
47
100
Err ( bonsaidb_files:: Error :: Database (
48
101
bonsaidb:: core:: Error :: UniqueKeyViolation { .. } ,
49
102
) ) 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 ?;
51
104
file. truncate ( 0 , Truncate :: RemovingStart ) . await ?;
52
105
break file;
53
106
}
54
107
Err ( bonsaidb_files:: Error :: Database (
55
108
bonsaidb:: core:: Error :: UniqueKeyViolation { .. } ,
56
109
) ) => continue ,
57
- Err ( err) => return Err ( err) ,
110
+ Err ( err) => return Err ( err. into ( ) ) ,
58
111
}
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)
60
121
}
61
122
}
0 commit comments