1 const mongodb = require("mongodb")
2 const cors = require("cors")
3 const morgan = require("morgan")
4 const hcaptcha = require("express-hcaptcha")
5 const express = require("express")
6 const socketIO = require("socket.io")
7 const httpError = require("http-errors")
8 const parseColor = require("color-parse")
12 const app = require("express")()
13 const server = require("http").createServer(app)
14 const mongoClient = new mongodb.MongoClient("mongodb://database:27017/myplace")
15 const io = new socketIO.Server(server)
17 const hcaptchaValidate = hcaptcha.middleware.validate(process.env.HCAPTCHA_SECRET_KEY)
19 app.use(morgan("tiny"))
20 app.set("view engine", "ejs")
21 app.use(express.static("public"))
22 app.use(express.static("node_modules/qrcode/build"))
23 app.use(express.urlencoded({extended: true}))
25 const getRoom = id => mongoClient.db().collection("rooms")
26 .findOne({_id: new mongodb.ObjectID.createFromHexString(id)})
28 const parseCoord = (size, max) => {
29 const x = parseInt(size.x)
30 const y = parseInt(size.y)
32 if (isNaN(x) || isNaN(y))
38 if (x >= max.x || y >= max.y)
44 app.get("/", cors(), (req, res) => {
45 res.render("create", {
47 hcaptcha_site_key: process.env.HCAPTCHA_SITE_KEY,
51 app.get("/room/:id/", (req, res) => getRoom(req.params.id).then(room => {
55 res.render("room", {id: room._id.toHexString()})
58 app.use("/create", (req, res, next) => {
59 req.body.token = req.body["h-captcha-response"]
63 app.post("/create", hcaptchaValidate, (req, res) => {
64 const timeout = parseInt(req.body.timeout)
65 const size = parseCoord({x: req.body.width, y: req.body.height}, {y: max_size, x: max_size})
67 if (isNaN(timeout) || timeout < 0)
68 throw httpError(400, "Invalid timeout")
71 throw httpError(400, "Invalid width or height")
73 mongoClient.db().collection("rooms")
78 const id = result.insertedId.toHexString()
79 const link = `${req.protocol}://${req.get("host")}/room/${id}/`
81 res.render("created", {id, link})
85 io.on("connection", socket => {
86 socket.on("join", id => getRoom(id).then(room => {
90 socket.emit("timeout", room.timeout)
91 socket.emit("size", room.size)
92 socket.emit("place", room.data)
93 socket.join(room._id.toHexString())
96 socket.on("place", ({id, x, y, color}) => getRoom(id).then(room => {
100 if (!color || !parseColor(color))
103 const pos = parseCoord({x, y}, room.size)
108 mongoClient.db().collection("rooms")
109 .updateOne({_id: room._id},
110 {"$set": {[`data.${pos.x}.${pos.y}`]: color}})
111 io.sockets.in(room._id.toHexString()).emit("place", {[pos.x]: {[pos.y]: color}})
115 mongoClient.connect().then(_ => {
116 server.listen(23430, _ => {
117 const address = server.address()
118 console.log("Listening on " + address.address + ":" + address.port)