1
1
use crate :: error:: { ApiError , ApiResult , ToApiResult } ;
2
+ use axum:: extract:: multipart:: Field ;
2
3
use axum:: extract:: Multipart ;
3
4
use chrono:: { DateTime , Utc } ;
4
5
use futures_util:: TryStreamExt ;
@@ -17,7 +18,7 @@ pub async fn store(
17
18
state : & ApiState ,
18
19
query : & UploadParamQuery ,
19
20
auth : Option < String > ,
20
- multipart : Multipart ,
21
+ mut multipart : Multipart ,
21
22
) -> ApiResult < ( FilePath , DateTime < Utc > ) > {
22
23
let auth = hash ( auth) ?;
23
24
let expire_secs = query
@@ -36,31 +37,52 @@ pub async fn store(
36
37
auth,
37
38
count_downloads : 0 ,
38
39
} ;
39
- let path = loop {
40
- let code = crate :: util:: string:: generate_random_string ( code_length) ;
41
- let path = FilePath {
42
- code,
43
- file_name : "TODO" . to_string ( ) ,
44
- } ;
45
- if state. db . exist ( & path) ? {
40
+ while let Ok ( Some ( field) ) = multipart. next_field ( ) . await {
41
+ let file_name = if let Some ( file_name) = field. file_name ( ) {
42
+ crate :: util:: file_name:: validate ( file_name) ?;
43
+ file_name. to_owned ( )
44
+ } else {
46
45
continue ;
47
- }
48
- match state. db . store ( path. clone ( ) , meta. clone ( ) ) . await {
49
- Ok ( _) => break path,
50
- Err ( ApiError :: ResourceExists ( e) ) => {
51
- debug ! ( "Key already exist: {e}" ) ;
46
+ } ;
47
+ let path = loop {
48
+ let code = crate :: util:: string:: generate_random_string ( code_length) ;
49
+ let path = FilePath {
50
+ code,
51
+ file_name : file_name. clone ( ) ,
52
+ } ;
53
+ if state. db . exist ( & path) ? {
52
54
continue ;
53
55
}
54
- Err ( e) => return Err ( e) ,
56
+ match state. db . store ( path. clone ( ) , meta. clone ( ) ) . await {
57
+ Ok ( _) => break path,
58
+ Err ( ApiError :: ResourceExists ( e) ) => {
59
+ debug ! ( "Key already exist: {e}" ) ;
60
+ continue ;
61
+ }
62
+ Err ( e) => return Err ( e) ,
63
+ }
64
+ } ;
65
+ let file_path = path. fs_path ( & state. config . fs . base_dir ) ;
66
+ if let Err ( e) = store_stream ( & file_path, field) . await {
67
+ state. db . delete ( path) . await ?;
68
+ return Err ( e) ;
55
69
}
56
- } ;
57
- let file_path = path. fs_path ( & state. config . fs . base_dir ) ;
58
- if let Err ( e) = store_stream ( & file_path, multipart) . await {
59
- state. db . delete ( path) . await ?;
60
- return Err ( e) ;
70
+ state. db . flush ( ) . await ?;
71
+ return Ok ( ( path, expiration_date) ) ;
61
72
}
62
- state. db . flush ( ) . await ?;
63
- Ok ( ( path, expiration_date) )
73
+ Err ( ApiError :: BadRequest ( "multpart is empty" . to_string ( ) ) )
74
+ }
75
+
76
+ pub async fn store_stream ( file_path : & PathBuf , field : Field < ' _ > ) -> ApiResult < ( ) > {
77
+ let body_with_io_error = field. map_err ( |err| std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , err) ) ;
78
+ let body_reader = StreamReader :: new ( body_with_io_error) ;
79
+ futures_util:: pin_mut!( body_reader) ;
80
+ if let Some ( p) = file_path. parent ( ) {
81
+ tokio:: fs:: create_dir_all ( p) . await ?;
82
+ }
83
+ let mut file = BufWriter :: new ( File :: create ( file_path) . await ?) ;
84
+ tokio:: io:: copy ( & mut body_reader, & mut file) . await ?;
85
+ Ok ( ( ) )
64
86
}
65
87
66
88
pub async fn info (
@@ -132,27 +154,6 @@ pub async fn delete(
132
154
Ok ( ( ) )
133
155
}
134
156
135
- pub async fn store_stream ( file_path : & PathBuf , mut multipart : Multipart ) -> ApiResult < ( ) > {
136
- while let Ok ( Some ( field) ) = multipart. next_field ( ) . await {
137
- let _file_name = if let Some ( file_name) = field. file_name ( ) {
138
- file_name. to_owned ( )
139
- } else {
140
- continue ;
141
- } ;
142
- let body_with_io_error =
143
- field. map_err ( |err| std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , err) ) ;
144
- let body_reader = StreamReader :: new ( body_with_io_error) ;
145
- futures_util:: pin_mut!( body_reader) ;
146
- if let Some ( p) = file_path. parent ( ) {
147
- tokio:: fs:: create_dir_all ( p) . await ?;
148
- }
149
- let mut file = BufWriter :: new ( File :: create ( file_path) . await ?) ;
150
- tokio:: io:: copy ( & mut body_reader, & mut file) . await ?;
151
- }
152
-
153
- Ok ( ( ) )
154
- }
155
-
156
157
pub async fn read_file ( file_path : & PathBuf ) -> ApiResult < ServeFile > {
157
158
Ok ( ServeFile :: new ( file_path) )
158
159
}
0 commit comments