test fcm v3

This commit is contained in:
amel
2025-06-30 14:39:00 +08:00
parent a4c22dc6fb
commit cc29622a23
9 changed files with 329 additions and 31 deletions

3
.env.test Normal file
View 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
View File

@@ -45,3 +45,6 @@ certificates
test.png
test2.png
xxx.ts
key.json

View File

@@ -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"
}

View File

@@ -1,5 +1,6 @@
import { sendFCM } from "@/lib/firebase/fcm";
import elysia from "elysia";
import { sendFCMNotification } from "../../../../../../xsend";
const ApiV2 = new elysia({
@@ -11,7 +12,7 @@ const ApiV2 = new elysia({
'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 {
data: "success elysia api"
};

View File

@@ -1,18 +1,11 @@
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)
if (!admin.apps.length) {
admin.initializeApp({
credential: admin.credential.cert({
projectId: process.env.GOOGLE_PROJECT_ID,
privateKey: decrypted,
privateKey: process.env.GOOGLE_PRIVATE_KEY?.replace(/\\n/g, '\n'),
clientEmail: process.env.GOOGLE_CLIENT_EMAIL,
}),
});

57
xsend.ts Normal file
View 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
View 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
View 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();

7
xx.ts
View File

@@ -1,7 +0,0 @@
import CryptoJS from "crypto-js";
const dataSource = process.env.GOOGLE_PRIVATE_KEY!
const encrypt = CryptoJS.AES.encrypt(dataSource, "amal").toString();
Bun.write("xencrypt.txt", encrypt);