181 lines
3.8 KiB
JavaScript
181 lines
3.8 KiB
JavaScript
require("dotenv").config();
|
|
|
|
const express = require("express");
|
|
const cors = require("cors");
|
|
const admin = require("firebase-admin");
|
|
const fs = require("fs");
|
|
|
|
const app = express();
|
|
|
|
app.use(cors());
|
|
app.use(express.json());
|
|
|
|
admin.initializeApp({
|
|
credential: admin.credential.cert(
|
|
require("./serviceAccountKey.json")
|
|
),
|
|
});
|
|
|
|
const API_KEY = process.env.API_KEY;
|
|
|
|
const TOKEN_FILE = "./tokens.json";
|
|
|
|
function loadTokens() {
|
|
try {
|
|
if (!fs.existsSync(TOKEN_FILE)) return [];
|
|
const data = fs.readFileSync(TOKEN_FILE, "utf8");
|
|
return JSON.parse(data || "[]");
|
|
} catch (err) {
|
|
console.error("[ERROR] Failed to load tokens:", err);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function saveTokens(tokens) {
|
|
try {
|
|
fs.writeFileSync(TOKEN_FILE, JSON.stringify(tokens, null, 2));
|
|
} catch (err) {
|
|
console.error("[ERROR] Failed to save tokens:", err);
|
|
}
|
|
}
|
|
|
|
let deviceTokens = new Set(loadTokens());
|
|
|
|
function authMiddleware(req, res, next) {
|
|
console.log("[INFO] Incoming request to /push");
|
|
const authHeader = req.headers.authorization;
|
|
|
|
if (!authHeader) {
|
|
return res.status(401).json({
|
|
error: "Missing Authorization Header",
|
|
});
|
|
}
|
|
|
|
const token = authHeader.replace("Bearer ", "");
|
|
|
|
if (token !== API_KEY) {
|
|
return res.status(403).json({
|
|
error: "Invalid API Key",
|
|
});
|
|
}
|
|
|
|
next();
|
|
}
|
|
|
|
app.post("/register-token", (req, res) => {
|
|
console.log("[INFO] /register-token called");
|
|
|
|
const { token, platform } = req.body;
|
|
|
|
if (!token) {
|
|
return res.status(400).json({
|
|
error: "token required",
|
|
});
|
|
}
|
|
|
|
deviceTokens.add(token);
|
|
|
|
saveTokens([...deviceTokens]);
|
|
|
|
console.log("[INFO] Token registered");
|
|
console.log("[DEBUG] Token:", token);
|
|
console.log("[DEBUG] Platform:", platform || "unknown");
|
|
console.log("[INFO] Total tokens:", deviceTokens.size);
|
|
|
|
res.json({
|
|
success: true,
|
|
count: deviceTokens.size,
|
|
});
|
|
});
|
|
|
|
app.post("/push", authMiddleware, async (req, res) => {
|
|
console.log("[INFO] /push called");
|
|
|
|
try {
|
|
const { type = "none", title, message } = req.body;
|
|
|
|
if (!title || !message) {
|
|
return res.status(400).json({
|
|
error: "title and message required",
|
|
});
|
|
}
|
|
|
|
if (deviceTokens.size === 0) {
|
|
return res.status(400).json({
|
|
error: "No registered device tokens",
|
|
});
|
|
}
|
|
|
|
let color = "#9e9e9e";
|
|
|
|
switch (type) {
|
|
case "info":
|
|
color = "#2196f3";
|
|
break;
|
|
case "warning":
|
|
color = "#ff9800";
|
|
break;
|
|
case "danger":
|
|
color = "#f44336";
|
|
break;
|
|
}
|
|
|
|
const messages = [];
|
|
|
|
for (const token of deviceTokens) {
|
|
messages.push({
|
|
token,
|
|
notification: {
|
|
title,
|
|
body: message,
|
|
},
|
|
data: {
|
|
type,
|
|
color,
|
|
},
|
|
android: {
|
|
priority: "high",
|
|
notification: { color },
|
|
},
|
|
apns: {
|
|
payload: {
|
|
aps: { sound: "default" },
|
|
},
|
|
},
|
|
webpush: {
|
|
notification: {
|
|
icon: "/icon-192.png",
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
console.log("[INFO] Sending messages...");
|
|
const response = await admin.messaging().sendEach(messages);
|
|
|
|
console.log("[INFO]:", response.successCount);
|
|
console.log("[ERROR]:", response.failureCount);
|
|
|
|
res.json({
|
|
success: true,
|
|
successCount: response.successCount,
|
|
failureCount: response.failureCount,
|
|
});
|
|
} catch (err) {
|
|
console.error("[ERROR] PUSH:", err);
|
|
|
|
res.status(500).json({
|
|
error: err.message,
|
|
});
|
|
}
|
|
});
|
|
|
|
const PORT = process.env.PORT || 3000;
|
|
|
|
app.listen(PORT, () => {
|
|
console.log("=================================");
|
|
console.log("Push Server started");
|
|
console.log("Port:", PORT);
|
|
console.log("Tokens:", TOKEN_FILE);
|
|
console.log("=================================");
|
|
}); |