Skip to content
Snippets Groups Projects
server.js 4.73 KiB
Newer Older
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) => {
Jonas Zohren's avatar
Jonas Zohren committed
  console.debug('[Debug] GET "/api/preview/:roomUid"');
  const constructedPath = path.join(
    __dirname,
    "room_previews",
    req.params.roomUid.split("/")[0].split("\\")[0] + ".jpeg"
Jonas Zohren's avatar
Jonas Zohren committed
  );
Jonas Zohren's avatar
Jonas Zohren committed
  console.debug('[Debug] constructed path:',constructedPath);
  res.setHeader("Cache-Control", "max-age=2");
  res.sendFile(constructedPath);
Jonas Zohren's avatar
Jonas Zohren committed
});

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
try {
  console.debug("[Debug] Running in", process.cwd());
  console.debug("[Debug] Running as", __filename);
  app.listen(PORT, () => {
    console.log(`Listening on port ${PORT}`);
  });
} catch (error) {
  console.error("Could not start to listen on port", PORT);
  throw error;
}