From 38f5d3b66ae56174c521a32a02e2e3c03ad00d46 Mon Sep 17 00:00:00 2001
From: unknown <pawel999@icloud.com>
Date: Wed, 19 May 2021 17:17:24 +0200
Subject: [PATCH] Added WebSockets with funcionality to send messages from any
 module

---
 Socket.js         | 21 +++++++++++++++++++++
 Sockets.js        | 20 ++++++++++++++++++++
 api.js            | 21 +++++++++++++++++++++
 package-lock.json |  5 +++++
 package.json      |  3 ++-
 server.js         | 33 +++++++++++++--------------------
 utils/jobs.js     |  2 ++
 7 files changed, 84 insertions(+), 21 deletions(-)
 create mode 100644 Socket.js
 create mode 100644 Sockets.js
 create mode 100644 api.js

diff --git a/Socket.js b/Socket.js
new file mode 100644
index 0000000..5b6d05c
--- /dev/null
+++ b/Socket.js
@@ -0,0 +1,21 @@
+const WebSocket = require('ws');
+
+class Socket {
+  constructor(server) {
+    this.webSocketServer = new WebSocket.Server({ server })
+
+    this.webSocketServer.on('listening', () => {
+      console.log('socket listen');
+    })
+
+    this.webSocketServer.on('connection', (webSocketClient) => {
+      console.log('new connection');
+    })
+  }
+
+  send(msg) {
+    this.webSocketServer.clients.forEach(client => client.send(msg));
+  }
+}
+
+module.exports = Socket;
\ No newline at end of file
diff --git a/Sockets.js b/Sockets.js
new file mode 100644
index 0000000..3457aa5
--- /dev/null
+++ b/Sockets.js
@@ -0,0 +1,20 @@
+class Sockets {
+  constructor() {
+    this.sockets = [];
+  }
+
+  registerSocket(name, socket) {
+    this.sockets.push({ name, socket });
+  }
+
+  getAllSockets() {
+    return this.sockets;
+  }
+
+  getSocket(name) {
+    const socket = this.sockets.find(socket => socket.name === name);
+    return socket;
+  }
+}
+
+module.exports = new Sockets();
\ No newline at end of file
diff --git a/api.js b/api.js
new file mode 100644
index 0000000..31151da
--- /dev/null
+++ b/api.js
@@ -0,0 +1,21 @@
+const express = require('express');
+const errorHandler = require('./middleware/errorHandler');
+
+const api = express();
+
+api.get('/', (req, res) => {
+  res.send('Server is working');
+})
+
+// Body parser
+api.use(express.json());
+
+// Link controllers with routes
+api.use('/api/apps', require('./routes/apps'));
+api.use('/api/config', require('./routes/config'));
+api.use('/api/weather', require('./routes/weather'));
+
+// Custom error handler
+api.use(errorHandler);
+
+module.exports = api;
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 9d9cbf5..4726a7e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2793,6 +2793,11 @@
         "typedarray-to-buffer": "^3.1.5"
       }
     },
+    "ws": {
+      "version": "7.4.5",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz",
+      "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g=="
+    },
     "xdg-basedir": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
diff --git a/package.json b/package.json
index c3e063f..e6c92ed 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,8 @@
     "express": "^4.17.1",
     "node-schedule": "^2.0.0",
     "sequelize": "^6.6.2",
-    "sqlite3": "^5.0.2"
+    "sqlite3": "^5.0.2",
+    "ws": "^7.4.5"
   },
   "devDependencies": {
     "nodemon": "^2.0.7"
diff --git a/server.js b/server.js
index d9e510f..a502846 100644
--- a/server.js
+++ b/server.js
@@ -1,30 +1,23 @@
-const express = require('express');
+const http = require('http');
 const { connectDB } = require('./db');
-const errorHandler = require('./middleware/errorHandler');
+const api = require('./api');
 const jobs = require('./utils/jobs');
-const colors = require('colors');
+const Socket = require('./Socket');
+const Sockets = require('./Sockets');
+
 require('dotenv').config();
+const PORT = process.env.PORT || 5005;
 
 connectDB();
 
-const app = express();
-const PORT = process.env.PORT || 5005;
+// Create server for Express API and WebSockets
+const server = http.createServer();
+server.on('request', api);
 
-app.get('/', (req, res) => {
-  res.send('Server is working');
-})
+// Register weatherSocket
+const weatherSocket = new Socket(server);
+Sockets.registerSocket('weather', weatherSocket);
 
-// Body parser
-app.use(express.json());
-
-// Link controllers with routes
-app.use('/api/apps', require('./routes/apps'));
-app.use('/api/config', require('./routes/config'));
-app.use('/api/weather', require('./routes/weather'));
-
-// Custom error handler
-app.use(errorHandler);
-
-app.listen(PORT, () => {
+server.listen(PORT, () => {
   console.log(`Server is running on port ${PORT} in ${process.env.NODE_ENV} mode`.yellow.bold);
 })
\ No newline at end of file
diff --git a/utils/jobs.js b/utils/jobs.js
index 1243f2f..4c4747e 100644
--- a/utils/jobs.js
+++ b/utils/jobs.js
@@ -1,10 +1,12 @@
 const schedule = require('node-schedule');
 const getExternalWeather = require('./getExternalWeather');
+const Sockets = require('../Sockets');
 
 const weatherJob = schedule.scheduleJob('updateWeather', '0 */15 * * * *', async () => {
   try {
     await getExternalWeather();
     console.log('weather updated');
+    Sockets.getSocket('weather').socket.send('weather updated');
   } catch (err) {
     console.log(err);
   }