371 lines
9.2 KiB
JavaScript
371 lines
9.2 KiB
JavaScript
const admin = require('firebase-admin');
|
||
|
||
let firebaseApp = null;
|
||
|
||
/**
|
||
* Firebase Admin SDK'yı başlat
|
||
*/
|
||
const initializeFirebase = () => {
|
||
try {
|
||
// Eğer zaten başlatılmışsa, mevcut instance'ı döndür
|
||
if (firebaseApp) {
|
||
return firebaseApp;
|
||
}
|
||
|
||
// Environment variables'dan Firebase config'i al
|
||
const firebaseConfig = {
|
||
type: process.env.FIREBASE_TYPE,
|
||
project_id: process.env.FIREBASE_PROJECT_ID,
|
||
private_key_id: process.env.FIREBASE_PRIVATE_KEY_ID,
|
||
private_key: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n'),
|
||
client_email: process.env.FIREBASE_CLIENT_EMAIL,
|
||
client_id: process.env.FIREBASE_CLIENT_ID,
|
||
auth_uri: process.env.FIREBASE_AUTH_URI,
|
||
token_uri: process.env.FIREBASE_TOKEN_URI,
|
||
auth_provider_x509_cert_url: process.env.FIREBASE_AUTH_PROVIDER_X509_CERT_URL,
|
||
client_x509_cert_url: process.env.FIREBASE_CLIENT_X509_CERT_URL
|
||
};
|
||
|
||
// Gerekli environment variables'ların varlığını kontrol et
|
||
const requiredFields = ['project_id', 'private_key', 'client_email'];
|
||
const missingFields = requiredFields.filter(field => !firebaseConfig[field]);
|
||
|
||
if (missingFields.length > 0) {
|
||
console.warn(`⚠️ Firebase konfigürasyonu eksik: ${missingFields.join(', ')}`);
|
||
console.warn('Push notification özelliği devre dışı bırakıldı.');
|
||
return null;
|
||
}
|
||
|
||
// Firebase Admin SDK'yı başlat
|
||
firebaseApp = admin.initializeApp({
|
||
credential: admin.credential.cert(firebaseConfig),
|
||
projectId: firebaseConfig.project_id
|
||
});
|
||
|
||
console.log('✅ Firebase Admin SDK başarıyla başlatıldı');
|
||
return firebaseApp;
|
||
|
||
} catch (error) {
|
||
console.error('❌ Firebase başlatma hatası:', error.message);
|
||
console.warn('Push notification özelliği devre dışı bırakıldı.');
|
||
return null;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Firebase Messaging instance'ını al
|
||
*/
|
||
const getMessaging = () => {
|
||
if (!firebaseApp) {
|
||
console.warn('Firebase başlatılmamış. Push notification gönderilemez.');
|
||
return null;
|
||
}
|
||
|
||
try {
|
||
return admin.messaging();
|
||
} catch (error) {
|
||
console.error('Firebase Messaging alınamadı:', error);
|
||
return null;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Tek bir cihaza push notification gönder
|
||
* @param {string} token - Device token
|
||
* @param {object} notification - Notification objesi
|
||
* @param {object} data - Ek veri
|
||
* @returns {Promise<object>} Gönderim sonucu
|
||
*/
|
||
const sendToDevice = async (token, notification, data = {}) => {
|
||
const messaging = getMessaging();
|
||
if (!messaging) {
|
||
return { success: false, error: 'Firebase Messaging kullanılamıyor' };
|
||
}
|
||
|
||
try {
|
||
const message = {
|
||
token: token,
|
||
notification: {
|
||
title: notification.title,
|
||
body: notification.body,
|
||
...(notification.imageUrl && { imageUrl: notification.imageUrl })
|
||
},
|
||
data: {
|
||
...data,
|
||
timestamp: new Date().toISOString()
|
||
},
|
||
android: {
|
||
notification: {
|
||
icon: 'ic_notification',
|
||
color: '#FF5722',
|
||
sound: 'default',
|
||
priority: 'high'
|
||
}
|
||
},
|
||
apns: {
|
||
payload: {
|
||
aps: {
|
||
sound: 'default',
|
||
badge: 1
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
const response = await messaging.send(message);
|
||
|
||
return {
|
||
success: true,
|
||
messageId: response,
|
||
token: token
|
||
};
|
||
|
||
} catch (error) {
|
||
console.error('Push notification gönderme hatası:', error);
|
||
|
||
// Token geçersizse, bu bilgiyi döndür
|
||
if (error.code === 'messaging/registration-token-not-registered' ||
|
||
error.code === 'messaging/invalid-registration-token') {
|
||
return {
|
||
success: false,
|
||
error: 'Invalid token',
|
||
invalidToken: true,
|
||
token: token
|
||
};
|
||
}
|
||
|
||
return {
|
||
success: false,
|
||
error: error.message,
|
||
token: token
|
||
};
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Birden fazla cihaza push notification gönder
|
||
* @param {string[]} tokens - Device token'ları
|
||
* @param {object} notification - Notification objesi
|
||
* @param {object} data - Ek veri
|
||
* @returns {Promise<object>} Gönderim sonucu
|
||
*/
|
||
const sendToMultipleDevices = async (tokens, notification, data = {}) => {
|
||
const messaging = getMessaging();
|
||
if (!messaging) {
|
||
return { success: false, error: 'Firebase Messaging kullanılamıyor' };
|
||
}
|
||
|
||
if (!tokens || tokens.length === 0) {
|
||
return { success: false, error: 'Token listesi boş' };
|
||
}
|
||
|
||
try {
|
||
const message = {
|
||
notification: {
|
||
title: notification.title,
|
||
body: notification.body,
|
||
...(notification.imageUrl && { imageUrl: notification.imageUrl })
|
||
},
|
||
data: {
|
||
...data,
|
||
timestamp: new Date().toISOString()
|
||
},
|
||
android: {
|
||
notification: {
|
||
icon: 'ic_notification',
|
||
color: '#FF5722',
|
||
sound: 'default',
|
||
priority: 'high'
|
||
}
|
||
},
|
||
apns: {
|
||
payload: {
|
||
aps: {
|
||
sound: 'default',
|
||
badge: 1
|
||
}
|
||
}
|
||
},
|
||
tokens: tokens
|
||
};
|
||
|
||
const response = await messaging.sendMulticast(message);
|
||
|
||
// Başarısız token'ları topla
|
||
const failedTokens = [];
|
||
const invalidTokens = [];
|
||
|
||
response.responses.forEach((resp, idx) => {
|
||
if (!resp.success) {
|
||
const token = tokens[idx];
|
||
failedTokens.push({ token, error: resp.error?.message });
|
||
|
||
if (resp.error?.code === 'messaging/registration-token-not-registered' ||
|
||
resp.error?.code === 'messaging/invalid-registration-token') {
|
||
invalidTokens.push(token);
|
||
}
|
||
}
|
||
});
|
||
|
||
return {
|
||
success: response.successCount > 0,
|
||
successCount: response.successCount,
|
||
failureCount: response.failureCount,
|
||
failedTokens: failedTokens,
|
||
invalidTokens: invalidTokens
|
||
};
|
||
|
||
} catch (error) {
|
||
console.error('Toplu push notification gönderme hatası:', error);
|
||
return {
|
||
success: false,
|
||
error: error.message
|
||
};
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Topic'e push notification gönder
|
||
* @param {string} topic - Topic adı
|
||
* @param {object} notification - Notification objesi
|
||
* @param {object} data - Ek veri
|
||
* @returns {Promise<object>} Gönderim sonucu
|
||
*/
|
||
const sendToTopic = async (topic, notification, data = {}) => {
|
||
const messaging = getMessaging();
|
||
if (!messaging) {
|
||
return { success: false, error: 'Firebase Messaging kullanılamıyor' };
|
||
}
|
||
|
||
try {
|
||
const message = {
|
||
topic: topic,
|
||
notification: {
|
||
title: notification.title,
|
||
body: notification.body,
|
||
...(notification.imageUrl && { imageUrl: notification.imageUrl })
|
||
},
|
||
data: {
|
||
...data,
|
||
timestamp: new Date().toISOString()
|
||
},
|
||
android: {
|
||
notification: {
|
||
icon: 'ic_notification',
|
||
color: '#FF5722',
|
||
sound: 'default',
|
||
priority: 'high'
|
||
}
|
||
},
|
||
apns: {
|
||
payload: {
|
||
aps: {
|
||
sound: 'default',
|
||
badge: 1
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
const response = await messaging.send(message);
|
||
|
||
return {
|
||
success: true,
|
||
messageId: response,
|
||
topic: topic
|
||
};
|
||
|
||
} catch (error) {
|
||
console.error('Topic push notification gönderme hatası:', error);
|
||
return {
|
||
success: false,
|
||
error: error.message,
|
||
topic: topic
|
||
};
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Cihazı topic'e abone et
|
||
* @param {string[]} tokens - Device token'ları
|
||
* @param {string} topic - Topic adı
|
||
* @returns {Promise<object>} Abonelik sonucu
|
||
*/
|
||
const subscribeToTopic = async (tokens, topic) => {
|
||
const messaging = getMessaging();
|
||
if (!messaging) {
|
||
return { success: false, error: 'Firebase Messaging kullanılamıyor' };
|
||
}
|
||
|
||
try {
|
||
const response = await messaging.subscribeToTopic(tokens, topic);
|
||
|
||
return {
|
||
success: response.successCount > 0,
|
||
successCount: response.successCount,
|
||
failureCount: response.failureCount,
|
||
errors: response.errors
|
||
};
|
||
|
||
} catch (error) {
|
||
console.error('Topic abonelik hatası:', error);
|
||
return {
|
||
success: false,
|
||
error: error.message
|
||
};
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Cihazın topic aboneliğini iptal et
|
||
* @param {string[]} tokens - Device token'ları
|
||
* @param {string} topic - Topic adı
|
||
* @returns {Promise<object>} Abonelik iptal sonucu
|
||
*/
|
||
const unsubscribeFromTopic = async (tokens, topic) => {
|
||
const messaging = getMessaging();
|
||
if (!messaging) {
|
||
return { success: false, error: 'Firebase Messaging kullanılamıyor' };
|
||
}
|
||
|
||
try {
|
||
const response = await messaging.unsubscribeFromTopic(tokens, topic);
|
||
|
||
return {
|
||
success: response.successCount > 0,
|
||
successCount: response.successCount,
|
||
failureCount: response.failureCount,
|
||
errors: response.errors
|
||
};
|
||
|
||
} catch (error) {
|
||
console.error('Topic abonelik iptal hatası:', error);
|
||
return {
|
||
success: false,
|
||
error: error.message
|
||
};
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Firebase durumunu kontrol et
|
||
* @returns {object} Firebase durum bilgisi
|
||
*/
|
||
const getStatus = () => {
|
||
return {
|
||
initialized: !!firebaseApp,
|
||
messaging: !!getMessaging(),
|
||
projectId: firebaseApp?.options?.projectId || null
|
||
};
|
||
};
|
||
|
||
module.exports = {
|
||
initializeFirebase,
|
||
getMessaging,
|
||
sendToDevice,
|
||
sendToMultipleDevices,
|
||
sendToTopic,
|
||
subscribeToTopic,
|
||
unsubscribeFromTopic,
|
||
getStatus
|
||
}; |