This commit is contained in:
2026-01-01 15:12:52 +01:00
commit 7bc14d7bbc
8 changed files with 169 additions and 0 deletions

12
src/firebase.ts Normal file
View File

@@ -0,0 +1,12 @@
import admin from "firebase-admin";
import serviceAccount from "../database-key.json";
admin.initializeApp({
credential: admin.credential.cert(
serviceAccount as admin.ServiceAccount
),
databaseURL: "https://pixel-battlegrounds-6c5a7-default-rtdb.firebaseio.com"
});
export const rtdb = admin.database();

41
src/index.ts Normal file
View File

@@ -0,0 +1,41 @@
import "dotenv/config";
import cron from "node-cron";
import { syncPlayers } from "./sync";
import { syncMongoToFirebase } from "./syncReverse"; // new function
async function main() {
const args = process.argv.slice(2);
if (args.includes("--one-time")) {
console.log("🔹 Running one-time Mongo → Firebase sync...");
try {
await syncMongoToFirebase();
console.log("✅ One-time sync finished");
} catch (e) {
console.error("One-time sync error:", e);
}
process.exit(0); // exit after one-time run
}
// Default: cron + immediate run
console.log("Firebase → Mongo sync running (every 15 minutes)");
// Run immediately
try {
await syncPlayers();
} catch (e) {
console.error("Players sync error:", e);
}
// Schedule every 15 minutes
cron.schedule("*/15 * * * *", async () => {
try {
await syncPlayers();
} catch (e) {
console.error("Players sync error:", e);
}
});
}
main();

14
src/mongo.ts Normal file
View File

@@ -0,0 +1,14 @@
import { MongoClient, Db } from "mongodb";
const uri = process.env.MONGO_URI!;
const client = new MongoClient(uri);
let db: Db | null = null;
export async function connectMongo(): Promise<Db> {
if (db) return db;
await client.connect();
db = client.db(); // database name is taken from URI
return db;
}

38
src/sync.ts Normal file
View File

@@ -0,0 +1,38 @@
import { rtdb } from "./firebase";
import { connectMongo } from "./mongo";
import { Document } from "mongodb";
type PlayerDoc = Document & { _id: number };
export async function syncPlayers() {
console.log("Players sync started:", new Date().toISOString());
const db = await connectMongo();
const collection = db.collection<PlayerDoc>("players");
// 🔹 RTDB path
const snapshot = await rtdb.ref("players").once("value");
const playersDict = snapshot.val();
if (!playersDict) {
console.log("No players data found");
return;
}
const bulkOps = Object.entries(playersDict).map(([id, data]) => ({
replaceOne: {
filter: { _id: Number(id) },
replacement: {
_id: Number(id),
...(data as object)
},
upsert: true
}
}));
await collection.bulkWrite(bulkOps, { ordered: false });
console.log("Players synced:", bulkOps.length);
}

24
src/syncReverse.ts Normal file
View File

@@ -0,0 +1,24 @@
import { rtdb } from "./firebase";
import { connectMongo } from "./mongo";
export async function syncMongoToFirebase() {
console.log("Mongo → Firebase sync started:", new Date().toISOString());
const db = await connectMongo();
const collection = db.collection("players");
const allPlayers = await collection.find().toArray();
// Convert to dictionary: { numericId: {...playerFields} }
const playersDict: Record<string, any> = {};
for (const player of allPlayers) {
const { _id, ...fields } = player;
playersDict[_id.toString()] = fields;
}
// Push to Firebase Realtime Database
await rtdb.ref("players").set(playersDict);
console.log("Mongo → Firebase sync finished:", allPlayers.length, "players");
}