const express = require("express"); const bodyParser = require("body-parser"); const cors = require("cors"); const path = require("path"); const cp = require("child_process"); const fs = require("fs"); const sleep = require("sleep-promise"); const PORT = 3000; const BOT_USERNAME = process.env.BOT_USERNAME; const BOT_PASSWORD = process.env.BOT_PASSWORD; const BOT_DISPLAY_NAME = process.env.BOT_DISPLAY_NAME || "Puppet"; // Global state: var attachedRooms = {}; async function attachToRoom(roomUrl) { // Get uid: const roomUid = roomUrl.split("/")[4]; // Make sure that no room get's attached to twice if (attachedRooms[roomUid] !== undefined) return; else attachedRooms[roomUid] = false; // Subprocess setup const subProcess = cp.fork(`${__dirname}/room_attacher.js`); subProcess.send({ eventName: "attachTo", data: { username: BOT_USERNAME, password: BOT_PASSWORD, displayName: BOT_DISPLAY_NAME, roomUrl, screenShotPath: "room_previews/" + roomUid + ".jpeg", }, }); const room = { subProcess, uid: roomUid, url: roomUrl, userCount: -1, users: [], name: "???", detach: async () => { try { subProcess.send({ eventName: "detach", data: null }); await sleep(500); subProcess.kill(0); } catch (error) { subProcess.kill(1); } }, sendMessage: (content) => { subProcess.send({ eventName: "sendMessage", data: { content } }); }, }; subProcess.on("message", (m) => { if (m.eventName === "roomInfo") { room.userCount = m.data.count; room.users = m.data.users; room.name = m.data.name; } else if (m.eventName === "sessionClosed") { attachedRooms[roomUid] = undefined; } else console.log("Room[" + roomUid + "]:", m); }); // return a room return room; } // Web server setup const app = express(); app.use(express.static("public")); app.use(bodyParser.json()); app.use(cors()); app.get("/api/preview/:roomUid", (req, res) => { res.setHeader("Cache-Control", "max-age=2"); res.sendFile( path.join( __dirname, "room_previews", req.params.roomUid.split("/")[0].split("\\")[0] + ".jpeg" ) ); }); app.post("/api/attach", async (req, res) => { const roomUrl = req.body.url; console.debug("Received request to attach to room", roomUrl); const room = await attachToRoom(roomUrl); attachedRooms[room.uid] = room; res.send({ uid: room.uid, url: roomUrl, }); }); app.post("/api/broadcast", (req, res) => { const content = "📢 Broadcast 📢\n\n" + req.body.content; console.debug("Received request to broadcast message", content); for (const roomUid of Object.keys(attachedRooms)) { if ( attachedRooms[roomUid] === undefined || attachedRooms[roomUid] === false ) continue; try { attachedRooms[roomUid].sendMessage(content); } catch (error) { console.warn('Could not send message "' + content + '" to room', roomUid); } } res.end({}); }); app.get("/api/attachedRooms", (req, res) => { const roomList = []; if (attachedRooms === undefined) { console.error("attachedRooms is undefined"); process.exit(1); } for (const key of Object.keys(attachedRooms)) { if (attachedRooms[key] === undefined) continue; roomList.push({ uid: attachedRooms[key].uid, url: attachedRooms[key].url, name: attachedRooms[key].name, userCount: attachedRooms[key].userCount, users: attachedRooms[key].users, }); } res.send(roomList); }); app.post("/api/detach", async (req, res) => { const roomUid = req.body.uid; if (attachedRooms[roomUid] !== undefined) { await attachedRooms[roomUid].detach(); attachedRooms[roomUid] = undefined; } res.send({}); }); app.post("/api/bulkcreate", async (req, res) => { const { prefix, amount } = req.body; }); app.listen(PORT, () => { console.log(`Example app listening at http://localhost:${PORT}`); });