Skip to content
Snippets Groups Projects
server.js 4.38 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jonas Zohren's avatar
    Jonas Zohren committed
    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 multer = require("multer");
    
    Jonas Zohren's avatar
    Jonas Zohren committed
    const sleep = require("sleep-promise");
    
    
    Jonas Zohren's avatar
    Jonas Zohren committed
    const PORT = process.env.PORT || 3000;
    const BOT_USERNAME =
      process.env.BOT_USERNAME ||
      console.error("Missing env BOT_USERNAME") ||
      process.exit(1);
    const BOT_PASSWORD =
      process.env.BOT_PASSWORD ||
      console.error("Missing env BOT_PASSWORD") ||
      process.exit(1);
    
    Jonas Zohren's avatar
    Jonas Zohren committed
    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());
    
    const fileUpload = multer({
      dest: "uploads/",
      limits: {
        fileSize: 30 * 1000 * 1000, // ~= 30 MB
      },
    });
    
    Jonas Zohren's avatar
    Jonas Zohren committed
    
    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.post(
      "/api/uploadPresentation",
      fileUpload.array("presentation", 10),
      async (req, res, next) => {
        console.debug(req.files);
        res.status(200).send({}).end();
        return;
      }
    );
    
    
    Jonas Zohren's avatar
    Jonas Zohren committed
    app.listen(PORT, () => {
    
    Jonas Zohren's avatar
    Jonas Zohren committed
      console.log(`Listening on port ${PORT}`);
    
    Jonas Zohren's avatar
    Jonas Zohren committed
    });