93 lines
3.9 KiB
Python
93 lines
3.9 KiB
Python
import logging
|
|
import os
|
|
import json
|
|
from google.cloud import firestore
|
|
from google.oauth2 import service_account
|
|
from src.core.config import settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class Database:
|
|
client = None
|
|
|
|
def connect_to_database(self):
|
|
"""Create database connection."""
|
|
try:
|
|
# Print project ID for debugging
|
|
logger.info(f"Attempting to connect to Firestore with project ID: {settings.FIRESTORE_PROJECT_ID}")
|
|
|
|
# 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)
|
|
# 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}")
|
|
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,
|
|
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}")
|
|
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()
|