test fcm v3
This commit is contained in:
3
.env.test
Normal file
3
.env.test
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
GOOGLE_PRIVATE_KEY_ID=764e1207d5acf4db2eac539256c8f1bf397c7d8f
|
||||||
|
GOOGLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwCU9PBpAbXsOl\ntb1syvWrmH3FSDRyI4oOVWZJRqYX+j44UTNfzTjYySpNy7x1lr91uOC2GGHJeFvT\nLg5er6uvzFvzwg42A8Rz4+aqxlUhvhNXYRyfaaP7tbui5X9GEmhKYzvYd6T/6z1u\njo7LE1tBaiB8eB69tSJidGcr90yXOsbvKFgaPkpvlrseNR/t0PYDUaXHsxdKvCHI\ntK13KxhJCJrU9+/W1Wwr+45WGfK9m+jLVuOEZT9dd3FUgDn/0CFzykZLA0iHRLjx\neczahlrlvLVCtUIJjHbmsjG8vLZyl6/puh1l2OkEZyADb6m7OOxFVTo5ADZvj4nD\nVCCirdMVAgMBAAECggEAMF0mbnJBpltnSkA/vkOWsmHPcCOx0QgFloGM/CXOXTkR\n3hwlDrWN4DWIi14ltXLIwFmeVzkkqJsKM19scEQ4WbC+NJ7Ek79+Ok7LYXDjE8Wq\nf6+9EukNtgqMdikySfilsYZI+2SHrw4czyKYhZ+YS0USjs/btkgtHbqYW+JyJvv4\nlXAGp3129kbOHTc6+DBq6tn4XiRMKUdBNtcRHe9k+zAIuwbeAdsl4bock1ADnMIv\n/Q4FfOua+nJl8MUpPCZDvz14az+3j/rUVkR/wgDqQirFNRfFfpEPNM2oXVSjp0oK\nTC8NEy5mN4aj0DYS8U2x8barsAFDr5N4L9JxTtdlgwKBgQDkXK9iieIe1/yJFDw6\ntHbQu/bl+t82DESapss62++6ckh2mo+IScvVg/rCwXIag7IRQO40BHWwYTrOwTbj\nD1VUamn6UaqJHpIjDj/SK+As3DumuOTcb+kbJq9TpjLGeR2hj0aKcFXAjL5+B+yr\nBt7fVsB2uhouS9aD68HV8azsxwKBgQDFV2yRKgSf11vNRsxtJekpZ7ruF4h8OZPA\nHcq1kMDPRJcuVD9XwG7RAEgxcErKKS6NrrT/2Iaq5r+P3owgxZ6yB5pabGGvsgcg\nqrvsVEjzETsrrDbp5IevwE/MTwplakr6vJBnfAyjqMbDQSGSZPp+6S8M5JtZhJDL\n9Pqy6yxNQwKBgEE9ZXGuWKZdKC11VXukAOnDOVcco9ZKDPNtwVPQb52BdshDgcv6\n4Tvfl606HMIMa7vYI/VCbOj17hoRQv/9anBScnJsEF9aF3/iW0NM+591T6li2ydK\n5Xq3Q5GPQqRHB7sXNpzoWOdIjkdtNiTqMpP1sch5hG9DhUZs/RSFFdUTAoGBALyV\nyD2NXu/1WVh5cQBZe1FDPMMtIBQ+3bB5h+8tDuTEEomGnyXX0s7OKy97tS0uX7us\nGnJo1IDblHMDZPwofnh5hYsmCdBiHCeeoYm+HhyS+e3JXIz2BKjy6g8/9ZpnEpI8\nwu7yAA4iSxfq1Q9Win/fjUQP71mDsvAGA9IZpbOLAoGBAK57RjNemVh3oNB5ZaQs\n45WzfmPPjKoDQdMYLtohHz9HhPxYFLuvlDc/9OcWFCz3tZHtyDrUtXvv+vX+rG4Y\nemxXkqdg3lYo7nayw772myJb2w6QIfGyuSRx/C1/phmPhp+UkHk7B+KdvWhpPmCC\nBufws2LSn5VZzivO6LrwSCfR\n-----END PRIVATE KEY-----\n"
|
||||||
|
GOOGLE_CLIENT_EMAIL=firebase-adminsdk-fbsvc@mobile-darmasaba.iam.gserviceaccount.com
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -45,3 +45,6 @@ certificates
|
|||||||
|
|
||||||
test.png
|
test.png
|
||||||
test2.png
|
test2.png
|
||||||
|
|
||||||
|
xxx.ts
|
||||||
|
key.json
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "service_account",
|
|
||||||
"project_id": "mobile-darmasaba",
|
|
||||||
"private_key_id": "764e1207d5acf4db2eac539256c8f1bf397c7d8f",
|
|
||||||
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwCU9PBpAbXsOl\ntb1syvWrmH3FSDRyI4oOVWZJRqYX+j44UTNfzTjYySpNy7x1lr91uOC2GGHJeFvT\nLg5er6uvzFvzwg42A8Rz4+aqxlUhvhNXYRyfaaP7tbui5X9GEmhKYzvYd6T/6z1u\njo7LE1tBaiB8eB69tSJidGcr90yXOsbvKFgaPkpvlrseNR/t0PYDUaXHsxdKvCHI\ntK13KxhJCJrU9+/W1Wwr+45WGfK9m+jLVuOEZT9dd3FUgDn/0CFzykZLA0iHRLjx\neczahlrlvLVCtUIJjHbmsjG8vLZyl6/puh1l2OkEZyADb6m7OOxFVTo5ADZvj4nD\nVCCirdMVAgMBAAECggEAMF0mbnJBpltnSkA/vkOWsmHPcCOx0QgFloGM/CXOXTkR\n3hwlDrWN4DWIi14ltXLIwFmeVzkkqJsKM19scEQ4WbC+NJ7Ek79+Ok7LYXDjE8Wq\nf6+9EukNtgqMdikySfilsYZI+2SHrw4czyKYhZ+YS0USjs/btkgtHbqYW+JyJvv4\nlXAGp3129kbOHTc6+DBq6tn4XiRMKUdBNtcRHe9k+zAIuwbeAdsl4bock1ADnMIv\n/Q4FfOua+nJl8MUpPCZDvz14az+3j/rUVkR/wgDqQirFNRfFfpEPNM2oXVSjp0oK\nTC8NEy5mN4aj0DYS8U2x8barsAFDr5N4L9JxTtdlgwKBgQDkXK9iieIe1/yJFDw6\ntHbQu/bl+t82DESapss62++6ckh2mo+IScvVg/rCwXIag7IRQO40BHWwYTrOwTbj\nD1VUamn6UaqJHpIjDj/SK+As3DumuOTcb+kbJq9TpjLGeR2hj0aKcFXAjL5+B+yr\nBt7fVsB2uhouS9aD68HV8azsxwKBgQDFV2yRKgSf11vNRsxtJekpZ7ruF4h8OZPA\nHcq1kMDPRJcuVD9XwG7RAEgxcErKKS6NrrT/2Iaq5r+P3owgxZ6yB5pabGGvsgcg\nqrvsVEjzETsrrDbp5IevwE/MTwplakr6vJBnfAyjqMbDQSGSZPp+6S8M5JtZhJDL\n9Pqy6yxNQwKBgEE9ZXGuWKZdKC11VXukAOnDOVcco9ZKDPNtwVPQb52BdshDgcv6\n4Tvfl606HMIMa7vYI/VCbOj17hoRQv/9anBScnJsEF9aF3/iW0NM+591T6li2ydK\n5Xq3Q5GPQqRHB7sXNpzoWOdIjkdtNiTqMpP1sch5hG9DhUZs/RSFFdUTAoGBALyV\nyD2NXu/1WVh5cQBZe1FDPMMtIBQ+3bB5h+8tDuTEEomGnyXX0s7OKy97tS0uX7us\nGnJo1IDblHMDZPwofnh5hYsmCdBiHCeeoYm+HhyS+e3JXIz2BKjy6g8/9ZpnEpI8\nwu7yAA4iSxfq1Q9Win/fjUQP71mDsvAGA9IZpbOLAoGBAK57RjNemVh3oNB5ZaQs\n45WzfmPPjKoDQdMYLtohHz9HhPxYFLuvlDc/9OcWFCz3tZHtyDrUtXvv+vX+rG4Y\nemxXkqdg3lYo7nayw772myJb2w6QIfGyuSRx/C1/phmPhp+UkHk7B+KdvWhpPmCC\nBufws2LSn5VZzivO6LrwSCfR\n-----END PRIVATE KEY-----\n",
|
|
||||||
"client_email": "firebase-adminsdk-fbsvc@mobile-darmasaba.iam.gserviceaccount.com",
|
|
||||||
"client_id": "105653213329235865762",
|
|
||||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
|
||||||
"token_uri": "https://oauth2.googleapis.com/token",
|
|
||||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
|
||||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40mobile-darmasaba.iam.gserviceaccount.com",
|
|
||||||
"universe_domain": "googleapis.com"
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { sendFCM } from "@/lib/firebase/fcm";
|
|
||||||
import elysia from "elysia";
|
import elysia from "elysia";
|
||||||
|
import { sendFCMNotification } from "../../../../../../xsend";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const ApiV2 = new elysia({
|
const ApiV2 = new elysia({
|
||||||
@@ -11,7 +12,7 @@ const ApiV2 = new elysia({
|
|||||||
'cRz96GHKTRaQaRJ35e8Hxa:APA91bEUSxE0VPbqKSzseQ_zGhbYsDofMexKykRw7o_3z2aPM9YFmZbeA2enrmb3qjdZ2g4-QQtiNHAyaZqAT1ITOrwo9jVJlShTeABmEFYP5GLEUZ3dlLc'
|
'cRz96GHKTRaQaRJ35e8Hxa:APA91bEUSxE0VPbqKSzseQ_zGhbYsDofMexKykRw7o_3z2aPM9YFmZbeA2enrmb3qjdZ2g4-QQtiNHAyaZqAT1ITOrwo9jVJlShTeABmEFYP5GLEUZ3dlLc'
|
||||||
]
|
]
|
||||||
|
|
||||||
sendFCM(token, "Test dari Production STG;", "Ini hanya percobaan notifikasi dari script.");
|
await sendFCMNotification('c89yuexsS_uc1tOErVPu5a:APA91bEb6tEKXAfReZjFVJ2mMyOzoW_RXryLSnSJTpbIVV3G0L_DCNkLuRvJ02Ip-Erz88QCQBAt-C2SN8eCRxu3-v1sBzXzKPtDv-huXpkjXsyrkifqvUo')
|
||||||
return {
|
return {
|
||||||
data: "success elysia api"
|
data: "success elysia api"
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
import admin from "firebase-admin";
|
import admin from "firebase-admin";
|
||||||
import dotenv from "dotenv";
|
|
||||||
dotenv.config({
|
|
||||||
path: ".env"
|
|
||||||
});
|
|
||||||
import CryptoJS from "crypto-js";
|
|
||||||
|
|
||||||
const privateKey = "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"
|
|
||||||
const decrypted = CryptoJS.AES.decrypt(privateKey, "amal").toString(CryptoJS.enc.Utf8);
|
|
||||||
// Inisialisasi admin (hanya sekali)
|
// Inisialisasi admin (hanya sekali)
|
||||||
if (!admin.apps.length) {
|
if (!admin.apps.length) {
|
||||||
admin.initializeApp({
|
admin.initializeApp({
|
||||||
credential: admin.credential.cert({
|
credential: admin.credential.cert({
|
||||||
projectId: process.env.GOOGLE_PROJECT_ID,
|
projectId: process.env.GOOGLE_PROJECT_ID,
|
||||||
privateKey: decrypted,
|
privateKey: process.env.GOOGLE_PRIVATE_KEY?.replace(/\\n/g, '\n'),
|
||||||
clientEmail: process.env.GOOGLE_CLIENT_EMAIL,
|
clientEmail: process.env.GOOGLE_CLIENT_EMAIL,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
57
xsend.ts
Normal file
57
xsend.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Impor Firebase Admin SDK
|
||||||
|
import { initializeApp, cert, getApp, getApps } from "firebase-admin/app";
|
||||||
|
import { getMessaging } from "firebase-admin/messaging";
|
||||||
|
import path from "path";
|
||||||
|
import fs from 'fs/promises'
|
||||||
|
|
||||||
|
|
||||||
|
// Fungsi untuk mengirim notifikasi FCM
|
||||||
|
export async function sendFCMNotification(token: string) {
|
||||||
|
const serviceAccount = await fs.readFile(path.join(process.cwd(), "key.json"));
|
||||||
|
if(getApps().length === 0){
|
||||||
|
initializeApp({
|
||||||
|
credential: cert(JSON.parse(serviceAccount.toString())),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Konfigurasi pesan
|
||||||
|
const message = {
|
||||||
|
notification: {
|
||||||
|
title: "Judul Notifikasi",
|
||||||
|
body: "Ini adalah isi notifikasi",
|
||||||
|
},
|
||||||
|
token,
|
||||||
|
data: {
|
||||||
|
key1: "value1",
|
||||||
|
key2: "value2",
|
||||||
|
},
|
||||||
|
// Opsional: konfigurasi Android
|
||||||
|
android: {
|
||||||
|
priority: "high",
|
||||||
|
notification: {
|
||||||
|
sound: "default",
|
||||||
|
channelId: "default_channel",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Opsional: konfigurasi APNS (iOS)
|
||||||
|
apns: {
|
||||||
|
payload: {
|
||||||
|
aps: {
|
||||||
|
sound: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Kirim pesan
|
||||||
|
const response = await getMessaging().send(message as any);
|
||||||
|
console.log("Notifikasi berhasil dikirim:", response);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error mengirim notifikasi:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendFCMNotification('c89yuexsS_uc1tOErVPu5a:APA91bEb6tEKXAfReZjFVJ2mMyOzoW_RXryLSnSJTpbIVV3G0L_DCNkLuRvJ02Ip-Erz88QCQBAt-C2SN8eCRxu3-v1sBzXzKPtDv-huXpkjXsyrkifqvUo')
|
||||||
116
xsendEach.ts
Normal file
116
xsendEach.ts
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import { initializeApp, cert } from "firebase-admin/app";
|
||||||
|
import { getMessaging } from "firebase-admin/messaging";
|
||||||
|
|
||||||
|
// Inisialisasi Firebase Admin
|
||||||
|
const serviceAccount = require("./key.json");
|
||||||
|
|
||||||
|
try {
|
||||||
|
initializeApp({
|
||||||
|
credential: cert(serviceAccount),
|
||||||
|
});
|
||||||
|
console.log("Firebase berhasil diinisialisasi");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Gagal inisialisasi Firebase:", error as Error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi untuk mengirim notifikasi ke banyak perangkat dengan retry
|
||||||
|
async function sendFCMEach(maxRetries = 3, retryDelay = 1000) {
|
||||||
|
try {
|
||||||
|
// Ganti dengan token perangkat yang valid
|
||||||
|
const tokens = [
|
||||||
|
'c89yuexsS_uc1tOErVPu5a:APA91bEb6tEKXAfReZjFVJ2mMyOzoW_RXryLSnSJTpbIVV3G0L_DCNkLuRvJ02Ip-Erz88QCQBAt-C2SN8eCRxu3-v1sBzXzKPtDv-huXpkjXsyrkifqvUo',
|
||||||
|
'cRz96GHKTRaQaRJ35e8Hxa:APA91bEUSxE0VPbqKSzseQ_zGhbYsDofMexKykRw7o_3z2aPM9YFmZbeA2enrmb3qjdZ2g4-QQtiNHAyaZqAT1ITOrwo9jVJlShTeABmEFYP5GLEUZ3dlLc'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Validasi token sebelum mengirim
|
||||||
|
const validTokens: string[] = [];
|
||||||
|
for (const token of tokens) {
|
||||||
|
try {
|
||||||
|
await getMessaging().send({
|
||||||
|
token,
|
||||||
|
notification: { title: "Test", body: "Validasi token" },
|
||||||
|
});
|
||||||
|
validTokens.push(token);
|
||||||
|
console.log(`Token ${token.slice(-4)} valid`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Token ${token.slice(-4)} tidak valid:`, error as Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validTokens.length === 0) {
|
||||||
|
throw new Error("Tidak ada token valid untuk mengirim notifikasi");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buat pesan untuk setiap token
|
||||||
|
const messages = validTokens.map((token) => ({
|
||||||
|
notification: {
|
||||||
|
title: "Judul Notifikasi",
|
||||||
|
body: `Pesan untuk perangkat ${token.slice(-4)}`,
|
||||||
|
},
|
||||||
|
token,
|
||||||
|
data: {
|
||||||
|
key1: "value1",
|
||||||
|
key2: "value2",
|
||||||
|
},
|
||||||
|
android: {
|
||||||
|
priority: "high",
|
||||||
|
notification: {
|
||||||
|
sound: "default",
|
||||||
|
channelId: "default_channel",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
apns: {
|
||||||
|
payload: {
|
||||||
|
aps: {
|
||||||
|
sound: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log("Mengirim notifikasi ke token:", validTokens.map((t) => t.slice(-4)));
|
||||||
|
|
||||||
|
// Kirim pesan dengan retry logic
|
||||||
|
let lastError;
|
||||||
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||||
|
try {
|
||||||
|
const response = await getMessaging().sendEach(messages as any);
|
||||||
|
console.log("Notifikasi berhasil dikirim:", response.successCount);
|
||||||
|
console.log("Notifikasi gagal:", response.failureCount);
|
||||||
|
|
||||||
|
response.responses.forEach((resp, index) => {
|
||||||
|
if (resp.success) {
|
||||||
|
console.log(`Pesan ke ${validTokens[index].slice(-4)} berhasil:`, resp.messageId);
|
||||||
|
} else {
|
||||||
|
console.error(`Pesan ke ${validTokens[index].slice(-4)} gagal:`, resp.error?.code, resp.error?.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
lastError = error;
|
||||||
|
console.error(`Percobaan ${attempt} gagal:`, error as Error);
|
||||||
|
if (attempt === maxRetries) {
|
||||||
|
throw new Error(`Gagal setelah ${maxRetries} percobaan: ${error as Error}`);
|
||||||
|
}
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw lastError;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error mengirim notifikasi:", error as Error);
|
||||||
|
if ((error as any).code === "messaging/registration-token-not-registered") {
|
||||||
|
console.log("Token tidak valid. Hapus token dari database.");
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jalankan fungsi
|
||||||
|
sendFCMEach()
|
||||||
|
.then(() => console.log("Proses selesai"))
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Gagal menjalankan sendFCMEach:", error as Error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
145
xsendEachV2.ts
Normal file
145
xsendEachV2.ts
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
import { initializeApp, cert } from "firebase-admin/app";
|
||||||
|
import { getMessaging } from "firebase-admin/messaging";
|
||||||
|
|
||||||
|
// Inisialisasi Firebase Admin
|
||||||
|
const serviceAccount = require("./key.json");
|
||||||
|
|
||||||
|
try {
|
||||||
|
initializeApp({
|
||||||
|
credential: cert(serviceAccount),
|
||||||
|
});
|
||||||
|
console.log("Firebase berhasil diinisialisasi");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Gagal inisialisasi Firebase:", (error as Error).message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi untuk menguji koneksi ke FCM server
|
||||||
|
async function testFCMConnection(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const response = await fetch("https://fcm.googleapis.com", { method: "GET" });
|
||||||
|
console.log("Koneksi ke FCM server:", response.status, response.statusText);
|
||||||
|
return response.ok;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Gagal menghubungi FCM server:", (error as Error).message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi untuk mengirim notifikasi ke banyak perangkat dengan retry
|
||||||
|
async function sendFCMEach(maxRetries: number = 5, retryDelay: number = 2000): Promise<any> {
|
||||||
|
try {
|
||||||
|
// Token perangkat
|
||||||
|
const tokens: string[] = [
|
||||||
|
"c89yuexsS_uc1tOErVPu5a:APA91bEb6tEKXAfReZjFVJ2mMyOzoW_RXryLSnSJTpbIVV3G0L_DCNkLuRvJ02Ip-Erz88QCQBAt-C2SN8eCRxu3-v1sBzXzKPtDv-huXpkjXsyrkifqvUo",
|
||||||
|
"cRz96GHKTRaQaRJ35e8Hxa:APA91bEUSxE0VPbqKSzseQ_zGhbYsDofMexKykRw7o_3z2aPM9YFmZbeA2enrmb3qjdZ2g4-QQtiNHAyaZqAT1ITOrwo9jVJlShTeABmEFYP5GLEUZ3dlLc",
|
||||||
|
];
|
||||||
|
|
||||||
|
// Validasi token sebelum mengirim
|
||||||
|
const validTokens: string[] = [];
|
||||||
|
for (const token of tokens) {
|
||||||
|
try {
|
||||||
|
await getMessaging().send({
|
||||||
|
token,
|
||||||
|
notification: { title: "Test", body: "Validasi token" },
|
||||||
|
});
|
||||||
|
validTokens.push(token);
|
||||||
|
console.log(`Token ${token.slice(-4)} valid`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Token ${token.slice(-4)} tidak valid:`, (error as Error).message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validTokens.length === 0) {
|
||||||
|
throw new Error("Tidak ada token valid untuk mengirim notifikasi");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buat pesan untuk setiap token
|
||||||
|
const messages = validTokens.map((token) => ({
|
||||||
|
notification: {
|
||||||
|
title: "Judul Notifikasi",
|
||||||
|
body: `Pesan untuk perangkat ${token.slice(-4)}`,
|
||||||
|
},
|
||||||
|
token,
|
||||||
|
data: {
|
||||||
|
key1: "value1",
|
||||||
|
key2: "value2",
|
||||||
|
},
|
||||||
|
android: {
|
||||||
|
priority: "high",
|
||||||
|
notification: {
|
||||||
|
sound: "default",
|
||||||
|
channelId: "default_channel",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
apns: {
|
||||||
|
payload: {
|
||||||
|
aps: {
|
||||||
|
sound: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log("Mengirim notifikasi ke token:", validTokens.map((t) => t.slice(-4)));
|
||||||
|
|
||||||
|
// Cek koneksi ke FCM server
|
||||||
|
const isConnected = await testFCMConnection();
|
||||||
|
if (!isConnected) {
|
||||||
|
throw new Error("Gagal terhubung ke FCM server. Periksa jaringan atau firewall.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kirim pesan dengan retry logic
|
||||||
|
let lastError: any;
|
||||||
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||||
|
try {
|
||||||
|
const response = await getMessaging().sendEach(messages as any);
|
||||||
|
console.log("Notifikasi berhasil dikirim:", response.successCount);
|
||||||
|
console.log("Notifikasi gagal:", response.failureCount);
|
||||||
|
|
||||||
|
response.responses.forEach((resp: any, index: number) => {
|
||||||
|
if (resp.success) {
|
||||||
|
console.log(`Pesan ke ${validTokens[index].slice(-4)} berhasil:`, resp.messageId);
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
`Pesan ke ${validTokens[index].slice(-4)} gagal:`,
|
||||||
|
resp.error?.code,
|
||||||
|
resp.error?.message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
lastError = error;
|
||||||
|
console.error(`Percobaan ${attempt} gagal:`, (error as Error).message);
|
||||||
|
if (error instanceof Error && (error as any).code === "app/network-error" && attempt < maxRetries) {
|
||||||
|
console.log(`Menunggu ${retryDelay}ms sebelum mencoba lagi...`);
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
||||||
|
} else {
|
||||||
|
throw new Error(`Gagal setelah ${maxRetries} percobaan: ${(error as Error).message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw lastError;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error mengirim notifikasi:", (error as Error).message, (error as Error).stack);
|
||||||
|
if ((error as any).code === "messaging/registration-token-not-registered") {
|
||||||
|
console.log("Token tidak valid. Hapus token dari database.");
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jalankan fungsi
|
||||||
|
async function main() {
|
||||||
|
try {
|
||||||
|
await sendFCMEach();
|
||||||
|
console.log("Proses selesai");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Gagal menjalankan sendFCMEach:", (error as Error).message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
Reference in New Issue
Block a user