o
    pj                     @  s  d Z ddlmZ ddlZddlZddlmZ ddlmZ ddl	m
Z
 ddlmZmZ ddlmZmZmZ dd	lmZ dd
lmZmZ e
eddZeddG dd dZG dd deZd3d4ddZd5dd Zd6d!d"Zd7d$d%Zd8d'd(Z d9d+d,Z!d:d.d/Z"ed;d1d2Z#dS )<z1Measured tenant storage with safe, atomic writes.    )annotationsN)contextmanager)	dataclass)Path)AnyIterator)caseor_select)get_control_plane_session)TenantTenantLimitPLATFORM_TENANT_STORAGE_ROOTz*/var/www/html/flask_server/storage/tenantsT)frozenc                   @  sX   e Zd ZU ded< ded< ded< ded< ded< ded	< d
ed< ded< dddZdS )StorageSnapshotstr	tenant_idstorage_keyrootint
used_bytesz
int | Nonelimit_bytesremaining_bytesfloat
percentagestatusreturndict[str, Any]c                 C  sv   d| j | j| jt| jd d d| j| jd u rd n	t| jd d d| j| jd u r+d n	t| jd d d| j| jdS )Nstorage_bytes      )metricr   r   usedused_mblimitlimit_mb	remainingremaining_mbr   r   )r   r   r   roundr   r   r   r   )self r*   =/var/www/html/flask_server/bridge_platform/storage/service.pyto_dict"   s     zStorageSnapshot.to_dictN)r   r   )__name__
__module____qualname____annotations__r,   r*   r*   r*   r+   r      s   
 r   c                      s   e Zd Zd	 fddZ  ZS )
StorageQuotaExceededsnapshotr   requested_bytesr   r   Nonec                   s,   || _ || _t d|j d| d d S )NzStorage quota exceeded: z bytes used, z bytes requested)r2   r3   super__init__r   )r)   r2   r3   	__class__r*   r+   r6   3   s   
zStorageQuotaExceeded.__init__)r2   r   r3   r   r   r4   )r-   r.   r/   r6   __classcell__r*   r*   r7   r+   r1   2   s    r1   r   r   app_id
str | Noner   c              
   C  s   t | |\}}}t|}t|}|d u rd nt|d d }|d u r$d ntd|| }|s/dntdt|| d d}	|d uoF||koF|dk}
t| |t|||||	|
rWdd	S dd	S )
Nr   r   g      Y@d   r    blockblocked	available)r   r   r   r   r   r   r   r   )	_storage_settings_tenant_root_directory_sizer   maxminr(   r   r   )r   r:   r   r%   policyr   r"   r   r&   r   r>   r*   r*   r+   get_storage_snapshot<   s&    rF   relative_path
str | Pathdatabytesr   c                 C  s  t | |\}}}t|}t||}t||}	|jddd t| t|}
|	 r/|	 jnd}|
| t	| }|du r?dnt
|d d }|dur_||kr_|dkr_t| |}t|t	||	jjddd tjd|	jd\}}z.t|d	}|| |  t|  W d   n1 sw   Y  t||	 W n ty   zt| W   ty   Y  w w W d   |	S 1 sw   Y  |	S )
zQuota-check and atomically write one tenant file.

    A filesystem lock prevents competing workers on the same shared volume
    from both accepting the same remaining capacity.
    T)parentsexist_okr   Nr   r=   z.upload-)prefixdirwb)r@   rA   _safe_childmkdir_tenant_lockrB   is_filestatst_sizelenr   rF   r1   parenttempfilemkstemposfdopenwriteflushfsyncfilenoreplace	ExceptionunlinkFileNotFoundError)r   r:   rG   rI   r   r%   rE   tenant_rootapp_rootdestinationr"   existing	projectedr   r2   fd	temp_namestreamr*   r*   r+   write_bytesP   sH   





rl   c                 C  sH   t | |\}}}t|}t||}t||}| s tt|| S )z5Read one file from the resolved tenant/app namespace.)r@   rA   rP   rS   rc   r   
read_bytes)r   r:   rG   r   _rd   re   sourcer*   r*   r+   rm   |   s   

rm   tuple[str, int | None, str]c              	   C  s   t  h}|t| }|d u rtd|  |r#ttj|ktjd ntjd }|t	t
tj| ktjdk|ttj|kdfddd }|jpT|jpT|j|rY|jnd |ra|jp`dndfW  d    S 1 snw   Y  d S )NzTenant not found: 
storage_mbr      )else_r=   	unlimited)r   getr   LookupErrorr	   r   r:   is_executer
   wherer   
limit_nameorder_byr   r$   scalar_one_or_noner   sluglimit_valueoverage_policy)r   r:   sessiontenantscoper$   r*   r*   r+   r@      s6   
	 $r@   r   c                 C  s
   t t| S N)rP   STORAGE_ROOT)r   r*   r*   r+   rA      s   
rA   r   childc                 C  s2   |   }||   }||kr||jvrtd|S )Nz$Storage path escapes the tenant root)resolverK   
ValueError)r   r   resolved_root	candidater*   r*   r+   rP      s
   rP   r   c              	   C  sZ   |   sdS d}| dD ]}z| r |jdkr || j7 }W q ty*   Y qw |S )Nr   *.quota.lock)existsrglobrS   namerT   rU   rc   )r   totalpathr*   r*   r+   rB      s   rB   Iterator[None]c                 c  s    dd l }| d }|d+}|| |j zd V  W || |j n
|| |j w W d    d S 1 s<w   Y  d S )Nr   r   za+b)fcntlopenflockr_   LOCK_EXLOCK_UN)r   r   	lock_pathlockr*   r*   r+   rR      s   *"rR   r   )r   r   r:   r;   r   r   )
r   r   r:   r   rG   rH   rI   rJ   r   r   )r   r   r:   r   rG   rH   r   rJ   )r   r   r:   r;   r   rp   )r   r   r   r   )r   r   r   rH   r   r   )r   r   r   r   )r   r   r   r   )$__doc__
__future__r   rZ   rX   
contextlibr   dataclassesr   pathlibr   typingr   r   
sqlalchemyr   r	   r
   config.control_planer   bridge_platform.tenants.modelsr   r   getenvr   r   PermissionErrorr1   rF   rl   rm   r@   rA   rP   rB   rR   r*   r*   r*   r+   <module>   s4    



,



