import { initializeApp, cert, getApps, getApp } from 'firebase-admin/app';
import { getFirestore, Firestore, collection, doc, setDoc, getDoc, updateDoc, query, where, orderBy, limit, onSnapshot } from 'firebase-admin/firestore';
import { getAuth, Auth } from 'firebase-admin/auth';
import { getFunctions, Functions } from 'firebase-admin/functions';
import { getStorage, Storage } from 'firebase-admin/storage';
interface FirebaseConfig {
projectId: string;
clientEmail: string;
privateKey: string;
databaseURL: string;
storageBucket: string;
}
export class EnterpriseFirebaseManager {
private app: any;
private firestore: Firestore;
private auth: Auth;
private functions: Functions;
private storage: Storage;
constructor(config: FirebaseConfig) {
this.app = !getApps().length ? initializeApp({
credential: cert({
projectId: config.projectId,
clientEmail: config.clientEmail,
privateKey: config.privateKey.replace(/\\n/g, '\n'),
}),
databaseURL: config.databaseURL,
storageBucket: config.storageBucket,
}) : getApp();
this.firestore = getFirestore(this.app);
this.auth = getAuth(this.app);
this.functions = getFunctions(this.app);
this.storage = getStorage(this.app);
}
async batchUpdateDocuments(
updates: Array<{ collection: string; docId: string; data: any }>
): Promise<void> {
const batch = this.firestore.batch();
for (const update of updates) {
const docRef = doc(this.firestore, update.collection, update.docId);
batch.set(docRef, {
...update.data,
updatedAt: new Date(),
updatedBy: 'system',
}, { merge: true });
}
await batch.commit();
}
subscribeToRealtimeUpdates<T>(
collectionPath: string,
filters: QueryFilter[] = [],
callback: (data: T[]) => void
): () => void {
let queryRef = collection(this.firestore, collectionPath);
for (const filter of filters) {
if (filter.type === 'where') {
queryRef = query(queryRef, where(filter.field, filter.operator, filter.value));
} else if (filter.type === 'orderBy') {
queryRef = query(queryRef, orderBy(filter.field, filter.direction));
} else if (filter.type === 'limit') {
queryRef = query(queryRef, limit(filter.value));
}
}
const unsubscribe = onSnapshot(
queryRef,
(snapshot) => {
const data: T[] = [];
snapshot.forEach((doc) => {
data.push({ id: doc.id, ...doc.data() } as T);
});
callback(data);
},
(error) => {
console.error('Real-time subscription error:', error);
}
);
return unsubscribe;
}
async authenticateUser(
uid: string,
customClaims: Record<string, any> = {}
): Promise<AuthResult> {
try {
await this.auth.setCustomUserClaims(uid, customClaims);
const userRecord = await this.auth.getUser(uid);
return {
success: true,
user: {
uid: userRecord.uid,
email: userRecord.email,
displayName: userRecord.displayName,
photoURL: userRecord.photoURL,
emailVerified: userRecord.emailVerified,
customClaims: userRecord.customClaims,
},
};
} catch (error) {
return {
success: false,
error: error.message,
};
}
}
async uploadFile(
filePath: string,
fileData: Buffer,
metadata: FileMetadata
): Promise<FileUploadResult> {
try {
const bucket = this.storage.bucket();
const file = bucket.file(filePath);
await file.save(fileData, {
metadata: {
contentType: metadata.contentType,
metadata: {
uploadedBy: metadata.uploadedBy,
originalName: metadata.originalName,
description: metadata.description,
tags: JSON.stringify(metadata.tags || []),
},
},
});
if (metadata.makePublic) {
await file.makePublic();
}
return {
success: true,
filePath,
publicUrl: metadata.makePublic ? file.publicUrl() : null,
size: fileData.length,
contentType: metadata.contentType,
};
} catch (error) {
return {
success: false,
error: error.message,
};
}
}
async callFunction(
functionName: string,
data: any,
timeout: number = 54000
): Promise<FunctionResult> {
try {
const functionRef = this.functions.httpsCallable(functionName);
const result = await functionRef(data);
return {
success: true,
data: result.data,
};
} catch (error) {
return {
success: false,
error: error.message,
code: error.code,
details: error.details,
};
}
}
}
export class RealtimeSyncManager {
private firebaseManager: EnterpriseFirebaseManager;
private syncSubscriptions: Map<string, () => void> = new Map();
constructor(firebaseManager: EnterpriseFirebaseManager) {
this.firebaseManager = firebaseManager;
}
syncUserData(userId: string, callback: (userData: UserData) => void): () => void {
const unsubscribe = this.firebaseManager.subscribeToRealtimeUpdates<UserData>(
`users/${userId}`,
[
{ type: 'orderBy', field: 'updatedAt', direction: 'desc' },
{ type: 'limit', value: 1 },
],
(data) => {
if (data.length > 0) {
callback(data[0]);
}
}
);
this.syncSubscriptions.set(`userData-${userId}`, unsubscribe);
return unsubscribe;
}
syncCollaborativeData(
documentId: string,
callback: (data: CollaborativeData) => void
): () => void {
const unsubscribe = this.firebaseManager.subscribeToRealtimeUpdates<CollaborativeData>(
`collaborative/${documentId}`,
[],
callback
);
this.syncSubscriptions.set(`collaborative-${documentId}`, unsubscribe);
return unsubscribe;
}
cancelAllSubscriptions(): void {
for (const unsubscribe of this.syncSubscriptions.values()) {
unsubscribe();
}
this.syncSubscriptions.clear();
}
}
export class FirestoreQueryOptimizer {
private firestore: Firestore;
constructor(firestore: Firestore) {
this.firestore = firestore;
}
async paginateWithCursor<T>(
collectionPath: string,
pageSize: number = 20,
startAfter?: string,
orderBy: string = 'createdAt'
): Promise<PaginatedResult<T>> {
let queryRef = collection(this.firestore, collectionPath);
queryRef = query(queryRef, orderBy(orderBy, 'desc'));
queryRef = query(queryRef, limit(pageSize + 1));
if (startAfter) {
const startDoc = await getDoc(doc(this.firestore, collectionPath, startAfter));
queryRef = query(queryRef, startAfter(startDoc));
}
const snapshot = await getDocs(queryRef);
const documents = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data(),
} as T));
const hasNext = documents.length > pageSize;
const data = hasNext ? documents.slice(0, -1) : documents;
return {
data,
hasNext,
nextCursor: hasNext ? documents[documents.length - 1].id : null,
};
}
async executeTransaction<T>(
operations: TransactionOperation[]
): Promise<T[]> {
const batch = this.firestore.batch();
for (const operation of operations) {
const docRef = doc(this.firestore, operation.collection, operation.docId);
switch (operation.type) {
case 'set':
batch.set(docRef, operation.data, operation.options);
break;
case 'update':
batch.update(docRef, operation.data);
break;
case 'delete':
batch.delete(docRef);
break;
}
}
await batch.commit();
return operations.map(op => op.data as T);
}
async executeCompositeQuery<T>(
queries: CompositeQuery[]
): Promise<CompositeQueryResult<T>> {
const results = await Promise.all(
queries.map(async (query) => {
let queryRef = collection(this.firestore, query.collection);
for (const filter of query.filters) {
queryRef = query(queryRef, where(filter.field, filter.operator, filter.value));
}
const snapshot = await getDocs(queryRef);
return {
key: query.key,
data: snapshot.docs.map(doc => ({
id: doc.id,
...doc.data(),
} as T)),
};
})
);
return {
results,
totalDocuments: results.reduce((sum, result) => sum + result.data.length, 0),
};
}
}
interface QueryFilter {
type: 'where' | 'orderBy' | 'limit';
field: string;
operator?: '==' | '!=' | '>' | '>=' | '<' | '<=' | 'array-contains' | 'in';
value?: any;
direction?: 'asc' | 'desc';
}
interface AuthResult {
success: boolean;
user?: {
uid: string;
email: string;
displayName: string;
photoURL: string;
emailVerified: boolean;
customClaims: Record<string, any>;
};
error?: string;
}
interface FileMetadata {
contentType: string;
uploadedBy: string;
originalName: string;
description?: string;
tags?: string[];
makePublic?: boolean;
}
interface FileUploadResult {
success: boolean;
filePath: string;
publicUrl?: string;
size: number;
contentType: string;
error?: string;
}
interface FunctionResult {
success: boolean;
data?: any;
error?: string;
code?: string;
details?: any;
}
interface UserData {
uid: string;
email: string;
displayName: string;
preferences: Record<string, any>;
lastActive: Date;
}
interface CollaborativeData {
documentId: string;
content: any;
collaborators: string[];
lastModified: Date;
modifiedBy: string;
}
interface PaginatedResult<T> {
data: T[];
hasNext: boolean;
nextCursor: string | null;
}
interface TransactionOperation {
type: 'set' | 'update' | 'delete';
collection: string;
docId: string;
data?: any;
options?: { merge?: boolean };
}
interface CompositeQuery {
key: string;
collection: string;
filters: QueryFilter[];
}
interface CompositeQueryResult<T> {
results: Array<{ key: string; data: T[] }>;
totalDocuments: number;
}
from firebase_functions import https_fn, firestore_fn, auth_fn, storage_fn
from firebase_admin import firestore, auth, storage
from google.cloud import pubsub_v1
from datetime import datetime, timedelta
import json
@https_fn.on_request()
def sync_realtime_data(request: https_fn.Request) -> https_fn.Response:
"""Handle real-time data synchronization requests."""
try:
data = request.get_json()
if not data or 'collection' not in data or 'document' not in data:
return https_fn.Response(
json.dumps({"error": "Missing required fields"}),
status=400,
mimetype="application/json"
)
db = firestore.client()
doc_ref = db.collection(data['collection']).document(data['document'])
doc_ref.set({
'data': data.get('data', {}),
'updated_at': datetime.utcnow(),
'sync_source': data.get('source', 'unknown'),
}, merge=True)
pubsub_client = pubsub_v1.PublisherClient()
topic_path = pubsub_client.topic_path(
os.environ.get('GCP_PROJECT', 'default-project'),
'realtime-updates'
)
pubsub_client.publish(
topic_path,
data=json.dumps({
'collection': data['collection'],
'document': data['document'],
'timestamp': datetime.utcnow().isoformat(),
}).encode('utf-8')
)
return https_fn.Response(
json.dumps({"success": True, "message": "Data synchronized successfully"}),
status=200,
mimetype="application/json"
)
except Exception as e:
return https_fn.Response(
json.dumps({"error": str(e)}),
status=500,
mimetype="application/json"
)
@auth_fn.on_user_created
def new_user_created(user: auth_fn.AuthEvent) -> None:
"""Handle new user creation."""
try:
db = firestore.client()
db.collection('users').document(user.uid).set({
'email': user.email,
'display_name': user.display_name,
'photo_url': user.photo_url,
'email_verified': user.email_verified,
'created_at': datetime.utcnow(),
'last_login': datetime.utcnow(),
'preferences': {
'notifications': True,
'theme': 'light',
'language': 'en',
},
'subscription_tier': 'free',
})
db.collection('user_stats').document(user.uid).set({
'documents_created': 0,
'collaborations': 0,
'last_activity': datetime.utcnow(),
})
except Exception as e:
print(f"Error creating user profile: {e}")
@storage_fn.on_object_finalized()
def process_uploaded_file(event: storage_fn.CloudEvent) -> None:
"""Process uploaded files and extract metadata."""
try:
file_path = event.data.name
bucket_name = event.data.bucket
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
blob = bucket.blob(file_path)
metadata = blob.metadata or {}
db = firestore.client()
db.collection('files').document(blob.name).set({
'name': blob.name,
'content_type': blob.content_type,
'size': blob.size,
'created': blob.time_created,
'updated': blob.updated,
'metadata': metadata,
'public_url': blob.public_url,
'processed': True,
})
if blob.content_type.startswith('image/'):
generate_thumbnail(blob.name)
except Exception as e:
print(f"Error processing file {event.data.name}: {e}")
def generate_thumbnail(file_path: str):
"""Generate thumbnail for uploaded images."""
try:
db = firestore.client()
db.collection('files').document(file_path).update({
'thumbnail_generated': True,
'thumbnail_url': f"https://storage.googleapis.com/thumbnails/{file_path}",
})
except Exception as e:
print(f"Error generating thumbnail for {file_path}: {e}")
@https_fn.on_request(schedule="0 2 * * *")
def automated_backup(request: https_fn.Request) -> https_fn.Response:
"""Perform automated database backup."""
try:
db = firestore.client()
backup_config = db.collection('config').document('backup').get().to_dict()
if not backup_config or not backup_config.get('enabled', False):
return https_fn.Response("Backup disabled", status=200)
backup_ref = db.collection('backups').document()
backup_ref.set({
'created_at': datetime.utcnow(),
'status': 'in_progress',
'type': 'automated',
'config': backup_config,
})
collections_to_backup = backup_config.get('collections', [])
backup_data = {}
for collection_name in collections_to_backup:
collection_ref = db.collection(collection_name)
docs = collection_ref.stream()
backup_data[collection_name] = [
{**doc.to_dict(), 'id': doc.id} for doc in docs
]
storage_client = storage.Client()
bucket = storage_client.bucket(backup_config['storage_bucket'])
backup_blob = bucket.blob(f"backups/{backup_ref.id}.json")
backup_blob.upload_from_string(
json.dumps(backup_data, default=str),
content_type='application/json'
)
backup_ref.update({
'status': 'completed',
'completed_at': datetime.utcnow(),
'storage_path': backup_blob.name,
'document_count': sum(len(docs) for docs in backup_data.values()),
})
clean_old_backups(backup_config['retention_days'])
return https_fn.Response(
json.dumps({
"success": True,
"backup_id": backup_ref.id,
"document_count": sum(len(docs) for docs in backup_data.values())
}),
status=200,
mimetype="application/json"
)
except Exception as e:
return https_fn.Response(
json.dumps({"error": str(e)}),
status=500,
mimetype="application/json"
)
def clean_old_backups(retention_days: int):
"""Clean old backup files."""
try:
cutoff_date = datetime.utcnow() - timedelta(days=retention_days)
db = firestore.client()
old_backups = db.collection('backups').where(
'created_at', '<', cutoff_date
).stream()
storage_client = storage.Client()
bucket = storage_client.bucket(os.environ.get('BACKUP_BUCKET'))
for backup in old_backups:
backup_path = backup.to_dict().get('storage_path')
if backup_path:
blob = bucket.blob(backup_path)
blob.delete()
db.collection('backups').document(backup.id).delete()
except Exception as e:
print(f"Error cleaning old backups: {e}")