1+ from datetime import UTC , datetime
12import re
23from time import time_ns
34
67
78from src .config import get_config
89
10+ # GOOGLE CLOUD STORAGE doesn't accept extreme datetime values like 3000 AD as custom time
11+ # For whoever sees this code in 2100 AD, please update the value!!!
12+ GCS_MAX_DATETIME_LIMIT = datetime (2100 , 10 , 31 , tzinfo = UTC )
913
1014class GoogleCloudStorage :
1115 client : Client
@@ -15,11 +19,18 @@ def __init__(self, bucket_name=get_config.cfg.google_cloud_services.storage_buck
1519 self .client = Client ()
1620 self .bucket = self .client .bucket (bucket_name )
1721
18- def upload_content (self , filename : str , content : bytes | str , content_type : str = "text/plain" ):
22+ def upload_content (self , filename : str , content : bytes | str , content_type : str = "text/plain" , is_anonymous : bool = False ):
1923 start_ns = time_ns ()
24+
2025 blob = self .bucket .blob (filename )
2126 blob .upload_from_string (data = content , content_type = content_type )
2227 blob .make_public ()
28+
29+ # We're using the file's custom time to have GCS automatically delete files associated with anonymous msgs
30+ if is_anonymous :
31+ blob .custom_time = datetime .now (UTC )
32+ blob .patch ()
33+
2334 end_ns = time_ns ()
2435
2536 current_app .logger .info ({
@@ -51,16 +62,76 @@ def delete_file(self, filename: str):
5162 })
5263
5364 def delete_multiple_files_by_url (self , file_urls : list [str ]):
65+ start_ns = time_ns ()
66+
5467 file_names = [re .sub (f"{ self .client .api_endpoint } /{ self .bucket .name } /" , "" , file_url ) for file_url in file_urls ]
55- self .bucket .delete_blobs (file_names )
68+
69+ found_blobs = []
70+ for name in file_names :
71+ blob = self .bucket .get_blob (blob_name = name )
72+ if (blob is not None ):
73+ found_blobs .append (blob )
74+
75+ blob_names = [blob .name for blob in found_blobs ]
76+
77+ try :
78+ self .bucket .delete_blobs (found_blobs )
79+ except Exception as e :
80+ current_app .logger .exception (
81+ f"Failed to delete { ',' .join (blob_names )} from the bucket:{ self .bucket .name } on GoogleCloudStorage" ,
82+ repr (e ),
83+ )
84+
85+ end_ns = time_ns ()
86+
87+ current_app .logger .info ({
88+ "service" : "GoogleCloudStorage" ,
89+ "action" : "batch_delete" ,
90+ "filename" : ',' .join (blob_names ),
91+ "duration_ms" : (end_ns - start_ns ) / 1_000_000 ,
92+ })
93+
94+ def update_file_deletion_time (self , filename : str , new_time : datetime ):
95+ if (new_time > GCS_MAX_DATETIME_LIMIT ):
96+ current_app .logger .info (
97+ f"The new datetime for { filename } is over GoogleCloudStorage limit"
98+ )
99+ raise Exception
100+
101+ start_ns = time_ns ()
102+ try :
103+ blob = self .bucket .get_blob (blob_name = filename )
104+ if blob is None :
105+ current_app .logger .error (
106+ f"Cannot find { filename } in the bucket:{ self .bucket .name } on GoogleCloudStorage" ,
107+ )
56108
57- def get_file_link (self , filename : str ):
58- blob = self .bucket .get_blob (blob_name = filename )
59- if blob is None :
109+ raise Exception
110+
111+ blob .custom_time = new_time
112+ blob .patch ()
113+
114+ except Exception as e :
60115 current_app .logger .error (
61- f"Cannot find { filename } in the bucket:{ self .bucket .name } on GoogleCloudStorage" ,
116+ f"Failed to update the metadata of { filename } in the bucket:{ self .bucket .name } on GoogleCloudStorage" ,
117+ repr (e ),
62118 )
63119
64120 return None
65121
66- return blob .public_url
122+ end_ns = time_ns ()
123+
124+ current_app .logger .info ({
125+ "service" : "GoogleCloudStorage" ,
126+ "action" : "update_file_deletion_time" ,
127+ "filename" : filename ,
128+ "duration_ms" : (end_ns - start_ns ) / 1_000_000 ,
129+ })
130+
131+
132+ def migrate_anonymous_file (self , filename : str ):
133+ current_app .logger .info (
134+ f"Migrating { filename } from anonymous to normal in the bucket:{ self .bucket .name } on GoogleCloudStorage" ,
135+ )
136+ # GCS doesn't allow unsetting custom time, instead we're setting it to the furthest time possible
137+ self .update_file_deletion_time (filename , GCS_MAX_DATETIME_LIMIT )
0 commit comments