Messenger_back_database / gdrive_storage.py
Nrighton233j
Add large file transfer via Google Drive (lazy pull, auto-delete)
d626f98
Raw
History Blame Contribute Delete
2.53 kB
"""
gdrive_storage.py — large file transfer (up to ~2GB) via a Google Drive
folder shared with a service account. Files are uploaded once, pulled
lazily by the recipient on tap, then permanently deleted from Drive —
nothing is ever shown to the user as a link; this is internal plumbing only.
"""
import os
import io
import json
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseUpload, MediaIoBaseDownload
SCOPES = ["https://www.googleapis.com/auth/drive"]
FOLDER_ID = os.environ.get("GDRIVE_FOLDER_ID")
SERVICE_ACCOUNT_JSON = os.environ.get("GDRIVE_SERVICE_ACCOUNT_JSON")
_service = None
def _get_service():
global _service
if _service is not None:
return _service
if not SERVICE_ACCOUNT_JSON:
raise RuntimeError("GDRIVE_SERVICE_ACCOUNT_JSON is not configured")
info = json.loads(SERVICE_ACCOUNT_JSON)
creds = service_account.Credentials.from_service_account_info(info, scopes=SCOPES)
_service = build("drive", "v3", credentials=creds)
return _service
def upload_large_file(file_bytes: bytes, filename: str, mime_type: str) -> dict:
"""Uploads a file into the shared Drive folder. Returns Drive file metadata."""
service = _get_service()
if not FOLDER_ID:
raise RuntimeError("GDRIVE_FOLDER_ID is not configured")
media = MediaIoBaseUpload(io.BytesIO(file_bytes), mimetype=mime_type, resumable=True)
metadata = {"name": filename, "parents": [FOLDER_ID]}
file = service.files().create(
body=metadata, media_body=media, fields="id, name, size"
).execute()
return file
def download_and_delete(file_id: str):
"""Streams a file's bytes back, then permanently deletes it from Drive.
Returns (bytes, filename)."""
service = _get_service()
meta = service.files().get(fileId=file_id, fields="name").execute()
filename = meta.get("name", "file")
request = service.files().get_media(fileId=file_id)
buffer = io.BytesIO()
downloader = MediaIoBaseDownload(buffer, request)
done = False
while not done:
_, done = downloader.next_chunk()
file_bytes = buffer.getvalue()
# Reclaim space immediately once fully downloaded
service.files().delete(fileId=file_id).execute()
return file_bytes, filename
def delete_file(file_id: str):
"""Used for cleanup of files that were never downloaded (expiry job)."""
service = _get_service()
service.files().delete(fileId=file_id).execute()