From cc29622a23c694e487d9ec1ecbdc19ef29fb099f Mon Sep 17 00:00:00 2001 From: amel Date: Mon, 30 Jun 2025 14:39:00 +0800 Subject: [PATCH] test fcm v3 --- .env.test | 3 + .gitignore | 5 +- service_key.json | 13 -- src/app/api/mobile/fcm/[[...slug]]/route.ts | 5 +- src/lib/firebase/fcm.ts | 9 +- xsend.ts | 57 ++++++++ xsendEach.ts | 116 ++++++++++++++++ xsendEachV2.ts | 145 ++++++++++++++++++++ xx.ts | 7 - 9 files changed, 329 insertions(+), 31 deletions(-) create mode 100644 .env.test delete mode 100644 service_key.json create mode 100644 xsend.ts create mode 100644 xsendEach.ts create mode 100644 xsendEachV2.ts delete mode 100644 xx.ts diff --git a/.env.test b/.env.test new file mode 100644 index 0000000..17d315a --- /dev/null +++ b/.env.test @@ -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 \ No newline at end of file diff --git a/.gitignore b/.gitignore index e30b04f..c6e47ff 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,7 @@ next-env.d.ts certificates test.png -test2.png \ No newline at end of file +test2.png + +xxx.ts +key.json diff --git a/service_key.json b/service_key.json deleted file mode 100644 index 76bd583..0000000 --- a/service_key.json +++ /dev/null @@ -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" -} diff --git a/src/app/api/mobile/fcm/[[...slug]]/route.ts b/src/app/api/mobile/fcm/[[...slug]]/route.ts index cbf64ba..c124bcf 100644 --- a/src/app/api/mobile/fcm/[[...slug]]/route.ts +++ b/src/app/api/mobile/fcm/[[...slug]]/route.ts @@ -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" }; diff --git a/src/lib/firebase/fcm.ts b/src/lib/firebase/fcm.ts index 0392058..1e8baf1 100644 --- a/src/lib/firebase/fcm.ts +++ b/src/lib/firebase/fcm.ts @@ -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, }), }); diff --git a/xsend.ts b/xsend.ts new file mode 100644 index 0000000..7a56fb9 --- /dev/null +++ b/xsend.ts @@ -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') \ No newline at end of file diff --git a/xsendEach.ts b/xsendEach.ts new file mode 100644 index 0000000..95403d3 --- /dev/null +++ b/xsendEach.ts @@ -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); + }); \ No newline at end of file diff --git a/xsendEachV2.ts b/xsendEachV2.ts new file mode 100644 index 0000000..35aedb8 --- /dev/null +++ b/xsendEachV2.ts @@ -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 { + 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 { + 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(); \ No newline at end of file diff --git a/xx.ts b/xx.ts deleted file mode 100644 index 9808d09..0000000 --- a/xx.ts +++ /dev/null @@ -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);