2025-05-24 12:06:57 +02:00

101 lines
4.4 KiB
Python

import logging
import os
import json
from google.cloud import firestore
from google.oauth2 import service_account
from src.config.config import settings
logger = logging.getLogger(__name__)
class Database:
client = None
database_name = None
def connect_to_database(self):
"""Create database connection."""
try:
# Store database name
self.database_name = settings.FIRESTORE_DATABASE_NAME
# Print project ID and database name for debugging
logger.info(f"Attempting to connect to Firestore with project ID: {settings.FIRESTORE_PROJECT_ID}, database: {self.database_name}")
# First try using Application Default Credentials (for Cloud environments)
try:
logger.info("Attempting to connect using Application Default Credentials")
self.client = firestore.Client(
project=settings.FIRESTORE_PROJECT_ID,
database=self.database_name
)
# Test connection by trying to access a collection
self.client.collection('test').limit(1).get()
logger.info(f"Connected to Firestore project using Application Default Credentials: {settings.FIRESTORE_PROJECT_ID}, database: {self.database_name}")
return
except Exception as adc_error:
logger.error(f"Application Default Credentials failed: {adc_error}", exc_info=True)
# Fall back to service account file
credentials_path = settings.FIRESTORE_CREDENTIALS_FILE
if not os.path.exists(credentials_path):
logger.error(f"Firestore credentials file not found: {credentials_path}")
raise FileNotFoundError(f"Credentials file not found: {credentials_path}")
# Print key file contents (without sensitive parts) for debugging
try:
with open(credentials_path, 'r') as f:
key_data = json.load(f)
# Log non-sensitive parts of the key
logger.info(f"Using credentials file with project_id: {key_data.get('project_id')}")
logger.info(f"Client email: {key_data.get('client_email')}")
logger.info(f"Key file type: {key_data.get('type')}")
except Exception as e:
logger.error(f"Error reading key file: {e}")
# Load credentials
credentials = service_account.Credentials.from_service_account_file(credentials_path)
# Initialize Firestore client
self.client = firestore.Client(
project=settings.FIRESTORE_PROJECT_ID,
database=self.database_name,
credentials=credentials
)
# Test connection by trying to access a collection
self.client.collection('test').limit(1).get()
logger.info(f"Connected to Firestore project using credentials file: {settings.FIRESTORE_PROJECT_ID}, database: {self.database_name}")
except Exception as e:
logger.error(f"Failed to connect to Firestore: {e}", exc_info=True)
raise
def close_database_connection(self):
"""Close database connection."""
try:
# No explicit close method needed for Firestore client
self.client = None
logger.info("Closed Firestore connection")
except Exception as e:
logger.error(f"Failed to close Firestore connection: {e}")
def get_database(self):
"""Get the database instance."""
if self.client is None:
logger.warning("Database client is None. Attempting to reconnect...")
try:
self.connect_to_database()
except Exception as e:
logger.error(f"Failed to reconnect to database: {e}")
# Return None to avoid further errors but log this issue
return None
# Verify that client is properly initialized
if self.client is None:
logger.error("Database client is still None after reconnect attempt")
return None
return self.client
# Create a singleton database instance
db = Database()