1+ from datetime import timedelta
2+ import datetime
13import io
24import tempfile
35import time
6+ from typing import Optional
47import urllib .parse as urlparse
58import aiohttp
69import anyio .abc
1114
1215from .abc import CPath , FileInfo , Storage
1316from miniopy_async import Minio
17+ from miniopy_async .api import BaseURL , presign_v4
1418from miniopy_async .datatypes import Object
1519from tianxiu2b2t import units
1620
@@ -39,14 +43,10 @@ def __init__(
3943 self .public_endpoint = kwargs .get ("public_endpoint" )
4044
4145 url = urlparse .urlparse (self .endpoint )
42-
43- self ._cache_files : UnboundTTLCache [str , FileInfo ] = UnboundTTLCache (
44- maxsize = int (units .parse_number_units (kwargs .get ("cache_size" , "10000" ))),
45- ttl = units .parse_time_units (kwargs .get ("cache_files_ttl" , "120s" ))
46- )
46+ self .ttl = units .parse_time_units (kwargs .get ("cache_ttl" , "1h" ))
4747 self ._cache : UnboundTTLCache [str , ResponseFile ] = UnboundTTLCache (
48- maxsize = int ( units .parse_number_units (kwargs .get ("cache_size" , "10000" ) )),
49- ttl = units . parse_time_units ( kwargs . get ( "cache_ttl" , "5m" ))
48+ maxsize = units .parse_number_units (kwargs .get ("cache_size" , "inf" )),
49+ ttl = self . ttl
5050 )
5151
5252 self .minio = Minio (
@@ -136,69 +136,98 @@ async def get_file(self, path: str) -> ResponseFile:
136136 file = self ._cache .get (cpath )
137137 if file is not None :
138138 return file
139- async with aiohttp .ClientSession () as session :
140- fileinfo = self ._cache_files .get (cpath )
141- resp = None
142- if not fileinfo :
143- resp = await self .minio .get_object (
144- self .bucket ,
145- cpath [1 :],
146- session ,
147- )
148- fileinfo = FileInfo (
149- name = cname ,
150- size = int (resp .headers .get ("content-length" ) or 0 ),
151- path = cpath ,
152- )
153- self ._cache_files [cpath ] = fileinfo
154- if self .custom_host is None and self .public_endpoint is None :
155- if resp is None :
156- resp = await self .minio .get_object (
157- self .bucket ,
158- cpath [1 :],
159- session ,
160- )
161- file = ResponseFileMemory (
162- data = await resp .read (),
163- size = fileinfo .size
164- )
165- resp .release ()
166- resp = None
167- if file is not None :
168- self ._cache [cpath ] = file
169- return file
170- if self .custom_host is not None :
139+ stat = await self .minio .stat_object (
140+ self .bucket ,
141+ cpath [1 :],
142+ )
143+ if stat .size == 0 :
144+ file = ResponseFileMemory (
145+ b"" ,
146+ 0
147+ )
148+ elif self .custom_host is not None :
171149 file = ResponseFileRemote (
172- f"{ self .custom_host } { cpath } " ,
173- fileinfo .size
150+ f"{ self .custom_host } / { self . bucket } { cpath } " ,
151+ int ( stat .size or 0 ),
174152 )
175153 elif self .public_endpoint is not None :
176- url = await self .minio .get_presigned_url (
154+ url = await get_presigned_url (
155+ self .minio ,
177156 "GET" ,
178157 self .bucket ,
179158 cpath [1 :],
180- )
181- urlobj = urlparse .urlparse (url )
182- # replace host
183- pub_urlobj = urlparse .urlparse (self .public_endpoint )
184- url : str = urlparse .urlunparse (
185- (
186- pub_urlobj .scheme or urlobj .scheme ,
187- pub_urlobj .netloc or urlobj .netloc ,
188- urlobj .path ,
189- urlobj .params ,
190- urlobj .query ,
191- urlobj .fragment ,
192- )
159+ region = self .region ,
160+ change_host = self .public_endpoint ,
193161 )
194162 file = ResponseFileRemote (
195163 url ,
196- fileinfo .size
164+ int ( stat .size or 0 ),
197165 )
198- if file is None :
199- return ResponseFileNotFound ()
166+ else :
167+ async with aiohttp .ClientSession () as session :
168+ async with (await self .minio .get_object (
169+ self .bucket ,
170+ cpath [1 :],
171+ session
172+ )) as resp :
173+ file = ResponseFileMemory (
174+ await resp .read (),
175+ int (stat .size or 0 ),
176+ )
200177 self ._cache [cpath ] = file
201178 return file
179+
180+
181+
202182
203183
204-
184+
185+
186+ async def get_presigned_url (
187+ minio : Minio ,
188+ method : str ,
189+ bucket_name : str ,
190+ object_name : str ,
191+ region : Optional [str ] = None ,
192+ expires : timedelta = timedelta (days = 7 ),
193+ request_date : Optional [datetime .datetime ] = None ,
194+ extra_query_params = None ,
195+ change_host = None ,
196+ ):
197+ if expires .total_seconds () < 1 or expires .total_seconds () > 604800 :
198+ raise ValueError ("expires must be between 1 second to 7 days" )
199+ region = region or await minio ._get_region (bucket_name , None )
200+ query_params = extra_query_params or {}
201+ creds = minio ._provider .retrieve () if minio ._provider else None
202+ if creds and creds .session_token :
203+ query_params ["X-Amz-Security-Token" ] = creds .session_token
204+ url = None
205+ if change_host :
206+ url = BaseURL (
207+ change_host ,
208+ region ,
209+ ).build (
210+ method ,
211+ region ,
212+ bucket_name = bucket_name ,
213+ object_name = object_name ,
214+ query_params = query_params ,
215+ )
216+ else :
217+ url = minio ._base_url .build (
218+ method ,
219+ region ,
220+ bucket_name = bucket_name ,
221+ object_name = object_name ,
222+ query_params = query_params ,
223+ )
224+ if creds :
225+ url = presign_v4 (
226+ method ,
227+ url ,
228+ region ,
229+ creds ,
230+ request_date or datetime .datetime .now (datetime .UTC ),
231+ int (expires .total_seconds ()),
232+ )
233+ return urlparse .urlunsplit (url )
0 commit comments