<file_sep>const path = require("path");

const config = {
  api: {
    port: 3000
  },
  timeout: 30 * 1000
};

module.exports = config;
<file_sep>const Router = require("express").Router;
const ws = require("../libs").ws;
const sockets = ws.sockets;
const router = Router();

router.post("/create", (req, res) => {
  const user = req.body;
  if (sockets.get(user.name)) {
    res.status(409);
    res.json("duplicate user name");
    return;
  }
  res.status(201);
  res.json({ name: user.name });
  return;
});

module.exports = router;
<file_sep># chatroom-server

## Features
 - Use node.js
 - Use docker

## Install
```bash
git clone <reop>
```

## Commands
 - Before development
```
npm install
```

 - Start server
```
node server.js
```

## Docker
 - Build docker image
 ```
 sh docker-build-backend.sh
 ```

 - Run image
 ```
 docker-compose up -d
 ```<file_sep>const WebSocket = require("ws");
const config = require("../config");
const HashMap = require("hashmap");
const sockets = new HashMap();
const cleanTasks = new HashMap();

const createCleanTask = (wss, type, name, message) => {
  const task = setTimeout(() => {
    const data = {
      type,
      name,
      message
    };
    wss.broadcast(JSON.stringify(data));
    const socket = sockets.get(name);
    socket.terminate();
    sockets.delete(name);
  }, config.timeout);
  return task;
};

module.exports = {
  sockets,
  setup: server => {
    wss = new WebSocket.Server({ server });

    wss.broadcast = data => {
      wss.clients.forEach(function each(client) {
        if (client.readyState === WebSocket.OPEN) {
          client.send(data);
        }
      });
    };

    wss.on("connection", socket => {
      socket.on("message", message => {
        const user = JSON.parse(message);
        if (user.login === true) {
          const data = {
            type: "system",
            name: user.name,
            message: `${user.name} enter the chat`
          };
          wss.broadcast(JSON.stringify(data));
          sockets.set(user.name, socket);
          cleanTasks.set(
            user.name,
            createCleanTask(
              wss,
              "system",
              user.name,
              `${user.name} was disconnected due to inactivity`
            )
          );
        }
        if (user.logout === true) {
          sockets.delete(user.name);
          clearTimeout(cleanTasks.get(user.name));
          cleanTasks.delete(user.name);
          const data = {
            type: "system",
            name: user.name,
            message: `${user.name} left the chat, connection lost`
          };
          wss.broadcast(JSON.stringify(data));
        }
        if (user.message) {
          clearTimeout(cleanTasks.get(user.name));
          cleanTasks.delete(user.name);
          cleanTasks.set(
            user.name,
            createCleanTask(
              wss,
              "system",
              user.name,
              `${user.name} was disconnected due to inactivity`
            )
          );
          wss.broadcast(JSON.stringify(user));
        }
      });
    });
  }
};
<file_sep>const config = require("./config");
const express = require("express");
const app = express();
const server = require("http").createServer(app);
const json = require("body-parser").json;
const urlencoded = require("body-parser").urlencoded;
const routes = require("./routes");
const ws = require("./libs").ws;
ws.setup(server);

app.use(json());
app.use(
  urlencoded({
    extended: false
  })
);

routes.setup(app);

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header(
    "Access-Control-Allow-Headers",
    "Authorization,Content-Type,Accept"
  );
  res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
  next();
});

app.use(function(err, req, res, next) {
  console.error({
    err
  });
  next();
});

process.on("uncaughtException", function(err) {
  console.error(err); // handle the error safely
});

// this function is called when you want the server to die gracefully
// i.e. wait for existing connections
var gracefulShutdown = function() {
  console.log("Received kill signal, shutting down gracefully.");
  server.close(function() {
    console.log("Closed out remaining connections.");
    process.exit()
  });
  
   // if after 
   setTimeout(function() {
       console.error("Could not close connections in time, forcefully shutting down");
       process.exit()
  }, 10*1000);
}

// listen for TERM signal .e.g. kill 
process.on ('SIGTERM', gracefulShutdown);

// listen for INT signal e.g. Ctrl-C
process.on ('SIGINT', gracefulShutdown);  

server.listen(config.api.port, function() {
  console.log(`Api server listening on port: ${config.api.port}`);
});
<file_sep>const express = require("express");
const chat = require("./chat");

const routes = {
  setup: app => {
    // setup routes
    const api = express.Router();
    api.use("/chat", chat);
    app.use("/api", api);
  }
};

module.exports = routes;
