11import logging
2- import os
32from contextlib import contextmanager
43from typing import Any , BinaryIO , Dict , List , Optional , Tuple
54
6- import boto3
75import psycopg2
8- from botocore .client import Config
9- from botocore .exceptions import ClientError
106from sqlalchemy import create_engine
117from sqlalchemy .orm import class_mapper , sessionmaker
128
2319 POSTGRES_USER ,
2420)
2521from database .db_models import TableBase
22+ from nexent .storage .storage_client_factory import create_storage_client_from_config , MinIOStorageConfig
23+
2624
2725logger = logging .getLogger ("database.client" )
2826
@@ -73,6 +71,12 @@ def clean_string_values(data: Dict[str, Any]) -> Dict[str, Any]:
7371
7472
7573class MinioClient :
74+ """
75+ MinIO client wrapper using storage SDK
76+
77+ This class maintains backward compatibility with the existing MinioClient interface
78+ while using the new storage SDK under the hood.
79+ """
7680 _instance : Optional ['MinioClient' ] = None
7781
7882 def __new__ (cls ):
@@ -81,39 +85,18 @@ def __new__(cls):
8185 return cls ._instance
8286
8387 def __init__ (self ):
84- self .endpoint = MINIO_ENDPOINT
85- self .access_key = MINIO_ACCESS_KEY
86- self .secret_key = MINIO_SECRET_KEY
87- self .region = MINIO_REGION
88- self .default_bucket = MINIO_DEFAULT_BUCKET
89-
90- # Initialize S3 client with proxy settings
91- self .client = boto3 .client (
92- 's3' ,
93- endpoint_url = self .endpoint ,
94- aws_access_key_id = self .access_key ,
95- aws_secret_access_key = self .secret_key ,
96- region_name = self .region ,
97- config = Config (
98- signature_version = 's3v4' ,
99- proxies = {
100- 'http' : None ,
101- 'https' : None
102- }
103- )
88+ # Determine if endpoint uses HTTPS
89+ secure = MINIO_ENDPOINT .startswith ('https://' ) if MINIO_ENDPOINT else True
90+ # Initialize storage client using SDK factory
91+ self .storage_config = MinIOStorageConfig (
92+ endpoint = MINIO_ENDPOINT ,
93+ access_key = MINIO_ACCESS_KEY ,
94+ secret_key = MINIO_SECRET_KEY ,
95+ region = MINIO_REGION ,
96+ default_bucket = MINIO_DEFAULT_BUCKET ,
97+ secure = secure
10498 )
105-
106- # Ensure default bucket exists
107- self ._ensure_bucket_exists (self .default_bucket )
108-
109- def _ensure_bucket_exists (self , bucket_name : str ) -> None :
110- """Ensure bucket exists, create if it doesn't"""
111- try :
112- self .client .head_bucket (Bucket = bucket_name )
113- except ClientError :
114- # Bucket doesn't exist, create it
115- self .client .create_bucket (Bucket = bucket_name )
116- logger .info (f"Created bucket: { bucket_name } " )
99+ self ._storage_client = create_storage_client_from_config (self .storage_config )
117100
118101 def upload_file (
119102 self ,
@@ -132,16 +115,7 @@ def upload_file(
132115 Returns:
133116 Tuple[bool, str]: (Success status, File URL or error message)
134117 """
135- bucket = bucket or self .default_bucket
136- if object_name is None :
137- object_name = os .path .basename (file_path )
138-
139- try :
140- self .client .upload_file (file_path , bucket , object_name )
141- file_url = f"/{ bucket } /{ object_name } "
142- return True , file_url
143- except Exception as e :
144- return False , str (e )
118+ return self ._storage_client .upload_file (file_path , object_name , bucket )
145119
146120 def upload_fileobj (self , file_obj : BinaryIO , object_name : str , bucket : Optional [str ] = None ) -> Tuple [bool , str ]:
147121 """
@@ -155,13 +129,7 @@ def upload_fileobj(self, file_obj: BinaryIO, object_name: str, bucket: Optional[
155129 Returns:
156130 Tuple[bool, str]: (Success status, File URL or error message)
157131 """
158- bucket = bucket or self .default_bucket
159- try :
160- self .client .upload_fileobj (file_obj , bucket , object_name )
161- file_url = f"/{ bucket } /{ object_name } "
162- return True , file_url
163- except Exception as e :
164- return False , str (e )
132+ return self ._storage_client .upload_fileobj (file_obj , object_name , bucket )
165133
166134 def download_file (self , object_name : str , file_path : str , bucket : Optional [str ] = None ) -> Tuple [bool , str ]:
167135 """
@@ -175,12 +143,7 @@ def download_file(self, object_name: str, file_path: str, bucket: Optional[str]
175143 Returns:
176144 Tuple[bool, str]: (Success status, Success message or error message)
177145 """
178- bucket = bucket or self .default_bucket
179- try :
180- self .client .download_file (bucket , object_name , file_path )
181- return True , f"File downloaded successfully to { file_path } "
182- except Exception as e :
183- return False , str (e )
146+ return self ._storage_client .download_file (object_name , file_path , bucket )
184147
185148 def get_file_url (self , object_name : str , bucket : Optional [str ] = None , expires : int = 3600 ) -> Tuple [bool , str ]:
186149 """
@@ -194,23 +157,20 @@ def get_file_url(self, object_name: str, bucket: Optional[str] = None, expires:
194157 Returns:
195158 Tuple[bool, str]: (Success status, Presigned URL or error message)
196159 """
197- bucket = bucket or self .default_bucket
198- try :
199- url = self .client .generate_presigned_url ('get_object' , Params = {'Bucket' : bucket , 'Key' : object_name },
200- ExpiresIn = expires )
201- return True , url
202- except Exception as e :
203- return False , str (e )
160+ return self ._storage_client .get_file_url (object_name , bucket , expires )
204161
205162 def get_file_size (self , object_name : str , bucket : Optional [str ] = None ) -> int :
206- bucket = bucket or self .default_bucket
207- try :
208- response = self .client .head_object (Bucket = bucket , Key = object_name )
209- return int (response ['ContentLength' ])
210- except ClientError as e :
211- logger .error (
212- f"Get file size by objectname({ object_name } ) failed: { e } " )
213- return 0
163+ """
164+ Get file size in bytes
165+
166+ Args:
167+ object_name: Object name
168+ bucket: Bucket name, if not specified use default bucket
169+
170+ Returns:
171+ int: File size in bytes, 0 if file not found or error
172+ """
173+ return self ._storage_client .get_file_size (object_name , bucket )
214174
215175 def list_files (self , prefix : str = "" , bucket : Optional [str ] = None ) -> List [dict ]:
216176 """
@@ -223,19 +183,7 @@ def list_files(self, prefix: str = "", bucket: Optional[str] = None) -> List[dic
223183 Returns:
224184 List[dict]: List of file information
225185 """
226- bucket = bucket or self .default_bucket
227- try :
228- response = self .client .list_objects_v2 (
229- Bucket = bucket , Prefix = prefix )
230- files = []
231- if 'Contents' in response :
232- for obj in response ['Contents' ]:
233- files .append (
234- {'key' : obj ['Key' ], 'size' : obj ['Size' ], 'last_modified' : obj ['LastModified' ]})
235- return files
236- except Exception as e :
237- logger .error (f"Error listing files: { str (e )} " )
238- return []
186+ return self ._storage_client .list_files (prefix , bucket )
239187
240188 def delete_file (self , object_name : str , bucket : Optional [str ] = None ) -> Tuple [bool , str ]:
241189 """
@@ -248,12 +196,7 @@ def delete_file(self, object_name: str, bucket: Optional[str] = None) -> Tuple[b
248196 Returns:
249197 Tuple[bool, str]: (Success status, Success message or error message)
250198 """
251- bucket = bucket or self .default_bucket
252- try :
253- self .client .delete_object (Bucket = bucket , Key = object_name )
254- return True , f"File { object_name } deleted successfully"
255- except Exception as e :
256- return False , str (e )
199+ return self ._storage_client .delete_file (object_name , bucket )
257200
258201 def get_file_stream (self , object_name : str , bucket : Optional [str ] = None ) -> Tuple [bool , Any ]:
259202 """
@@ -266,12 +209,7 @@ def get_file_stream(self, object_name: str, bucket: Optional[str] = None) -> Tup
266209 Returns:
267210 Tuple[bool, Any]: (Success status, File stream object or error message)
268211 """
269- bucket = bucket or self .default_bucket
270- try :
271- response = self .client .get_object (Bucket = bucket , Key = object_name )
272- return True , response ['Body' ]
273- except Exception as e :
274- return False , str (e )
212+ return self ._storage_client .get_file_stream (object_name , bucket )
275213
276214
277215# Create global database and MinIO client instances
0 commit comments