4
4
import typing as T
5
5
import urllib
6
6
from logging import getLogger
7
- from time import mktime
8
7
from urllib .parse import urlsplit , urlunsplit
9
8
10
9
import minio
14
13
from django .core .files .storage import Storage
15
14
from django .utils import timezone
16
15
from django .utils .deconstruct import deconstructible
17
- from minio .helpers import get_target_url
18
16
19
17
from minio_storage .errors import minio_error
20
18
from minio_storage .files import ReadOnlySpooledTemporaryFile
@@ -109,15 +107,16 @@ def _create_base_url_client(client: minio.Minio, bucket_name: str, base_url: str
109
107
base_url_parts = urlsplit (base_url )
110
108
111
109
# Clone from the normal client, but with base_url as the endpoint
110
+ credentials = client ._provider .retrieve ()
112
111
base_url_client = minio .Minio (
113
112
base_url_parts .netloc ,
114
- access_key = client . _access_key ,
115
- secret_key = client . _secret_key ,
116
- session_token = client . _session_token ,
113
+ access_key = credentials . access_key ,
114
+ secret_key = credentials . secret_key ,
115
+ session_token = credentials . session_token ,
117
116
secure = base_url_parts .scheme == "https" ,
118
117
# The bucket region may be auto-detected by client (via an HTTP
119
118
# request), so don't just use client._region
120
- region = client ._get_bucket_region (bucket_name ),
119
+ region = client ._get_region (bucket_name , None ),
121
120
http_client = client ._http ,
122
121
)
123
122
if hasattr (client , "_credentials" ):
@@ -151,7 +150,7 @@ def _examine_file(self, name, content):
151
150
def _open (self , name , mode = "rb" ):
152
151
try :
153
152
f = self .file_class (self ._sanitize_path (name ), mode , self )
154
- except merr .MinioError as e :
153
+ except merr .MinioException as e :
155
154
raise minio_error ("File {} could not be saved: {}" .format (name , str (e )), e )
156
155
return f
157
156
@@ -169,14 +168,14 @@ def _save(self, name: str, content: bytes) -> str:
169
168
metadata = self .object_metadata ,
170
169
)
171
170
return sane_name
172
- except merr .ResponseError as error :
171
+ except merr .InvalidResponseError as error :
173
172
raise minio_error (f"File { name } could not be saved" , error )
174
173
175
174
def delete (self , name : str ) -> None :
176
175
if self .backup_format and self .backup_bucket :
177
176
try :
178
177
obj = self .client .get_object (self .bucket_name , name )
179
- except merr .ResponseError as error :
178
+ except merr .InvalidResponseError as error :
180
179
raise minio_error (
181
180
"Could not obtain file {} " "to make a copy of it" .format (name ),
182
181
error ,
@@ -195,7 +194,7 @@ def delete(self, name: str) -> None:
195
194
self .client .put_object (
196
195
self .backup_bucket , target_name , obj , content_length
197
196
)
198
- except merr .ResponseError as error :
197
+ except merr .InvalidResponseError as error :
199
198
raise minio_error (
200
199
"Could not make a copy of file "
201
200
"{} before removing it" .format (name ),
@@ -204,22 +203,22 @@ def delete(self, name: str) -> None:
204
203
205
204
try :
206
205
self .client .remove_object (self .bucket_name , name )
207
- except merr .ResponseError as error :
206
+ except merr .InvalidResponseError as error :
208
207
raise minio_error (f"Could not remove file { name } " , error )
209
208
210
209
def exists (self , name : str ) -> bool :
211
210
try :
212
211
self .client .stat_object (self .bucket_name , self ._sanitize_path (name ))
213
212
return True
214
- except merr .ResponseError as error :
213
+ except merr .InvalidResponseError as error :
215
214
# TODO - deprecate
216
215
if error .code == "NoSuchKey" :
217
216
return False
218
217
else :
219
218
raise minio_error (f"Could not stat file { name } " , error )
220
- except merr .NoSuchKey :
219
+ except merr .S3Error :
221
220
return False
222
- except merr .NoSuchBucket :
221
+ except merr .S3Error :
223
222
raise
224
223
except Exception as error :
225
224
logger .error (error )
@@ -242,24 +241,24 @@ def listdir(self, path: str) -> T.Tuple[T.List, T.List]:
242
241
dirs : T .List [str ] = []
243
242
files : T .List [str ] = []
244
243
try :
245
- objects = self .client .list_objects_v2 (self .bucket_name , prefix = path )
244
+ objects = self .client .list_objects (self .bucket_name , prefix = path )
246
245
for o in objects :
247
246
p = posixpath .relpath (o .object_name , path )
248
247
if o .is_dir :
249
248
dirs .append (p )
250
249
else :
251
250
files .append (p )
252
251
return dirs , files
253
- except merr .NoSuchBucket :
252
+ except merr .S3Error :
254
253
raise
255
- except merr .ResponseError as error :
254
+ except merr .InvalidResponseError as error :
256
255
raise minio_error (f"Could not list directory { path } " , error )
257
256
258
257
def size (self , name : str ) -> int :
259
258
try :
260
259
info = self .client .stat_object (self .bucket_name , name )
261
260
return info .size
262
- except merr .ResponseError as error :
261
+ except merr .InvalidResponseError as error :
263
262
raise minio_error (f"Could not access file size for { name } " , error )
264
263
265
264
def _presigned_url (
@@ -279,7 +278,7 @@ def _presigned_url(
279
278
# It's assumed that self.base_url will contain bucket information,
280
279
# which could be different, so remove the bucket_name component (with 1
281
280
# extra character for the leading "/") from the generated URL
282
- url_key_path = url_parts .path [len (self .bucket_name ) + 1 :]
281
+ url_key_path = url_parts .path [len (self .bucket_name ) + 1 :]
283
282
284
283
# Prefix the URL with any path content from base_url
285
284
new_url_path = base_url_parts .path + url_key_path
@@ -302,30 +301,33 @@ def url(
302
301
if self .presign_urls :
303
302
url = self ._presigned_url (name , max_age = max_age )
304
303
else :
305
- if self .base_url is not None :
304
+ def strip_beg (path ):
305
+ while path .startswith ("/" ):
306
+ path = path [1 :]
307
+ return path
306
308
307
- def strip_beg (path ):
308
- while path .startswith ("/" ):
309
- path = path [1 : ]
310
- return path
309
+ def strip_end (path ):
310
+ while path .endswith ("/" ):
311
+ path = path [: - 1 ]
312
+ return path
311
313
312
- def strip_end (path ):
313
- while path .endswith ("/" ):
314
- path = path [:- 1 ]
315
- return path
314
+ if self .base_url is not None :
316
315
317
316
url = "{}/{}" .format (
318
317
strip_end (self .base_url ), urllib .parse .quote (strip_beg (name ))
319
318
)
320
319
else :
321
- url = get_target_url (
322
- self .client ._endpoint_url ,
323
- bucket_name = self .bucket_name ,
324
- object_name = name ,
325
- # bucket_region=region,
320
+ url = "{}/{}/{}" .format (
321
+ strip_end (self .endpoint_url ),
322
+ self .bucket_name ,
323
+ urllib .parse .quote (strip_beg (name )),
326
324
)
327
325
return url
328
326
327
+ @property
328
+ def endpoint_url (self ):
329
+ return self .client ._base_url ._url .geturl ()
330
+
329
331
def accessed_time (self , name : str ) -> datetime .datetime :
330
332
"""
331
333
Not available via the S3 API
@@ -341,8 +343,8 @@ def created_time(self, name: str) -> datetime.datetime:
341
343
def modified_time (self , name : str ) -> datetime .datetime :
342
344
try :
343
345
info = self .client .stat_object (self .bucket_name , name )
344
- return datetime . datetime . fromtimestamp ( mktime ( info .last_modified ))
345
- except merr .ResponseError as error :
346
+ return info .last_modified
347
+ except merr .InvalidResponseError as error :
346
348
raise minio_error (
347
349
f"Could not access modification time for file { name } " , error
348
350
)
0 commit comments