o
    i,                     @   s   d Z ddlmZ ddlmZ ddlmZmZ ddlZddl	m
Z
 ddlZddlmZ eeZG dd	 d	Zdad
efddZdS )uH   
MinIO 对象存储服务
用于存储和管理税务文档原始文件
    )Minio)S3Error)OptionalBinaryION)	timedelta)StorageErrorc                   @   sL  e Zd ZdZ				d/dedededefd	d
ZdeddfddZ	d0dededede	dedefddZ
	d0dededededef
ddZdedededefddZdededee fddZdededefddZdededefd d!Zed"d#fdeded$edee fd%d&Z	'	(d1ded)ed*edefd+d,Zded)ede	fd-d.ZdS )2MinioServiceu   MinIO 对象存储服务类localhost:9000
minioadminFendpoint
access_key
secret_keysecurec              
   C   sl   || _ || _|| _|| _zt||||d| _td|  W dS  ty5 } z	t	d|   d}~ww )u   
        初始化 MinIO 客户端

        Args:
            endpoint: MinIO 服务器地址
            access_key: 访问密钥
            secret_key: 密钥
            secure: 是否使用 HTTPS
        r   r   r   r   z!Successfully connected to MinIO: zFailed to connect to MinIO: N)
r   r   r   r   r   clientloggerinfo	Exceptionerror)selfr   r   r   r   e r   B/lsinfo/ai/hellotax_ai/base_platform/app/services/storage/minio.py__init__   s"   zMinioService.__init__bucket_namereturnNc              
   C   s   z"| j |s| j | td|  W dS td|  W dS  tyD } ztd| d|  tdt| |dd}~ww )u   
        确保存储桶存在，如果不存在则创建

        Args:
            bucket_name: 存储桶名称

        Raises:
            StorageError: 如果创建存储桶失败
        zCreated bucket: zBucket already exists: zFailed to create bucket : zFailed to create bucket: bucketN)	r   bucket_existsmake_bucketr   r   r   r   r   str)r   r   r   r   r   r   ensure_bucket4   s   
zMinioService.ensure_bucketapplication/octet-streamobject_name	file_data	file_sizecontent_typec              
   C   st   z|  | | jj|||||d td| d|  W dS  ty9 } ztd|  W Y d}~dS d}~ww )u:  
        上传文件到 MinIO

        Args:
            bucket_name: 存储桶名称
            object_name: 对象名称（文件路径）
            file_data: 文件数据流
            file_size: 文件大小
            content_type: 文件类型

        Returns:
            是否上传成功
        )r   r$   datalengthr'   File uploaded successfully: /TFile upload failed: NF)r"   r   
put_objectr   r   r   r   )r   r   r$   r%   r&   r'   r   r   r   r   upload_fileH   s    
zMinioService.upload_file	file_pathc              
   C   sr   z|  | | jj||||d td| d|  W dS  ty8 } ztd|  W Y d}~dS d}~ww )u(  
        从本地路径上传文件到 MinIO

        Args:
            bucket_name: 存储桶名称
            object_name: 对象名称（文件路径）
            file_path: 本地文件路径
            content_type: 文件类型

        Returns:
            是否上传成功
        )r   r$   r/   r'   r*   r+   Tr,   NF)r"   r   fput_objectr   r   r   r   )r   r   r$   r/   r'   r   r   r   r   upload_file_from_patho   s   
z"MinioService.upload_file_from_pathc              
   C   sl   z| j j|||d td| d| d|  W dS  ty5 } ztd|  W Y d}~dS d}~ww )	u   
        从 MinIO 下载文件到本地

        Args:
            bucket_name: 存储桶名称
            object_name: 对象名称（文件路径）
            file_path: 本地保存路径

        Returns:
            是否下载成功
        )r   r$   r/   zFile downloaded successfully: r+   z -> TzFile download failed: NF)r   fget_objectr   r   r   r   )r   r   r$   r/   r   r   r   r   download_file   s   zMinioService.download_filec              
   C   s|   z"| j j||d}| }|  |  td| d|  |W S  ty= } ztd|  W Y d}~dS d}~ww )u   
        获取文件数据（不保存到本地）

        Args:
            bucket_name: 存储桶名称
            object_name: 对象名称（文件路径）

        Returns:
            文件数据，失败返回 None
        r   r$   z"File data retrieved successfully: r+   zFailed to get file data: N)	r   
get_objectreadcloserelease_connr   r   r   r   )r   r   r$   responser(   r   r   r   r   get_file_data   s   zMinioService.get_file_datac              
   C   sd   z| j j||d td| d|  W dS  ty1 } ztd|  W Y d}~dS d}~ww )u   
        删除文件

        Args:
            bucket_name: 存储桶名称
            object_name: 对象名称（文件路径）

        Returns:
            是否删除成功
        r4   zFile deleted successfully: r+   TzFile deletion failed: NF)r   remove_objectr   r   r   r   )r   r   r$   r   r   r   r   delete_file   s   zMinioService.delete_filec                 C   s,   z| j j||d W dS  ty   Y dS w )u   
        检查文件是否存在

        Args:
            bucket_name: 存储桶名称
            object_name: 对象名称（文件路径）

        Returns:
            文件是否存在
        r4   TF)r   stat_objectr   )r   r   r$   r   r   r   file_exists   s   zMinioService.file_exists   )hoursexpiresc              
   C   sf   z| j j|||d}td| d|  |W S  ty2 } ztd|  W Y d}~dS d}~ww )u  
        获取文件的预签名 URL（用于临时访问）

        Args:
            bucket_name: 存储桶名称
            object_name: 对象名称（文件路径）
            expires: 过期时间

        Returns:
            预签名 URL，失败返回 None
        )r   r$   rA   zGenerated presigned URL: r+   z"Failed to generate presigned URL: N)r   presigned_get_objectr   r   r   r   )r   r   r$   rA   urlr   r   r   r   get_presigned_url   s   zMinioService.get_presigned_url Tprefix	recursivec              
   C   s|   z!| j j|||d}g }|D ]}||j|j|j|jd q|W S  ty= } zt	d|  g W  Y d}~S d}~ww )u   
        列出存储桶中的对象

        Args:
            bucket_name: 存储桶名称
            prefix: 对象名称前缀（用于过滤）
            recursive: 是否递归列出

        Returns:
            对象列表
        r   rF   rG   )r$   sizelast_modifiedetagzFailed to list objects: N)
r   list_objectsappendr$   rI   rJ   rK   r   r   r   )r   r   rF   rG   objectsresultobjr   r   r   r   rL     s(   
zMinioService.list_objectsc           	   
      s\  ddl m  zd| jj||dd} fdd|D }|s)td| d|  W dS t| j||}|rVd	d |D }td
t	| d|  t
d
t	| d| |dt	|}td| d| d|  |W S  t
yr     ty } z0t|dddkrtd| d|  W Y d}~dS td| d|  t
dt| |dd}~ww )u   
        按前缀批量删除 MinIO 对象

        Args:
            bucket_name: 存储桶名称
            prefix: 对象名称前缀，如 "tenant_3/kb_11/"

        Returns:
            删除的对象数量
        r   DeleteObjectTrH   c                    s   g | ]} |j qS r   r$   ).0rP   rQ   r   r   
<listcomp>V  s    z1MinioService.delete_by_prefix.<locals>.<listcomp>zNo objects found with prefix: r+   c                 S   s   g | ]}|j qS r   rS   )rT   r   r   r   r   rU   ]  s    zFailed to delete z
 objects: z objects under prefix r   zDeleted z objects with prefix: coderE   NoSuchBucketz-Bucket does not exist, skip prefix deletion: Nz#Failed to delete objects by prefix r   z$Failed to delete objects by prefix: )minio.deleteobjectsrR   r   rL   r   r   listremove_objectsr   lenr   r   getattrr!   )	r   r   rF   rN   delete_listerrorserror_namesdeleted_countr   r   rQ   r   delete_by_prefix@  s@   zMinioService.delete_by_prefix)r	   r
   r
   F)r#   )rE   T)__name__
__module____qualname____doc__r!   boolr   r"   r   intr.   r1   r3   r   bytesr:   r<   r>   r   rD   rY   rL   ra   r   r   r   r   r      s    
!
,
$




 
$r   r   c                  C   s8   t du rddlm}  t| j| j| j| j dkda t S )uG   获取 MinIO 服务实例（单例模式，从 settings 读取配置）Nr   settingstruer   )	_minio_service
app.configrj   r   MINIO_ENDPOINTMINIO_ACCESS_KEYMINIO_SECRET_KEYMINIO_SECURElowerri   r   r   r   get_minio_servicev  s   rs   )re   minior   minio.errorr   typingr   r   loggingdatetimer   ioapp.core.exceptionsr   	getLoggerrb   r   r   rl   rs   r   r   r   r   <module>   s    
  e