Przeglądaj źródła

impl middlewares to check connection limits

Yuki Takei 5 lat temu
rodzic
commit
8d7e751de5
1 zmienionych plików z 63 dodań i 12 usunięć
  1. 63 12
      src/server/service/socket-io.js

+ 63 - 12
src/server/service/socket-io.js

@@ -3,6 +3,9 @@ const expressSession = require('express-session');
 const passport = require('passport');
 const socketioSession = require('@kobalab/socket.io-session');
 
+const logger = require('@alias/logger')('growi:service:socket-io');
+
+
 /**
  * Serve socket.io for server-to-client messaging
  */
@@ -12,8 +15,6 @@ class SocketIoService {
     this.crowi = crowi;
     this.configManager = crowi.configManager;
 
-    this.connectionsCount = 0;
-    this.connectionsCountForAdmin = 0;
     this.connectionsCountForGuest = 0;
   }
 
@@ -35,6 +36,8 @@ class SocketIoService {
     this.setupLoginRequiredMiddleware();
     this.setupAdminRequiredMiddleware();
     this.setupCheckConnectionLimitsMiddleware();
+
+    this.setupCountConnectionEventHandler();
   }
 
   getDefaultSocket() {
@@ -67,8 +70,8 @@ class SocketIoService {
    * use loginRequired middleware
    */
   setupLoginRequiredMiddleware() {
-    const loginRequired = require('../middlewares/login-required')(this.crowi, true, (req, res) => {
-      throw new Error('Login is required to connect.');
+    const loginRequired = require('../middlewares/login-required')(this.crowi, true, (req, res, next) => {
+      next(new Error('Login is required to connect.'));
     });
 
     // convert Connect/Express middleware to Socket.io middleware
@@ -81,8 +84,8 @@ class SocketIoService {
    * use adminRequired middleware
    */
   setupAdminRequiredMiddleware() {
-    const adminRequired = require('../middlewares/admin-required')(this.crowi, (req, res) => {
-      throw new Error('Admin priviledge is required to connect.');
+    const adminRequired = require('../middlewares/admin-required')(this.crowi, (req, res, next) => {
+      next(new Error('Admin priviledge is required to connect.'));
     });
 
     // convert Connect/Express middleware to Socket.io middleware
@@ -95,9 +98,19 @@ class SocketIoService {
    * use checkConnectionLimits middleware
    */
   setupCheckConnectionLimitsMiddleware() {
+    this.io.use(this.checkConnectionLimitsForAdmin.bind(this));
+    this.io.use(this.checkConnectionLimitsForGuest.bind(this));
     this.io.use(this.checkConnectionLimits.bind(this));
   }
 
+  setupCountConnectionEventHandler() {
+    this.io.on('connection', (socket) => {
+      if (socket.request.user == null) {
+        this.connectionsCountForGuest++;
+      }
+    });
+  }
+
   async getClients(namespace) {
     return new Promise((resolve, reject) => {
       namespace.clients((error, clients) => {
@@ -109,20 +122,58 @@ class SocketIoService {
     });
   }
 
+  async checkConnectionLimitsForAdmin(socket, next) {
+    const namespaceName = socket.nsp.name;
+
+    if (namespaceName === '/admin') {
+      const clients = await this.getClients(this.getAdminSocket());
+      const clientsCount = clients.length;
+
+      logger.debug('Current clients for \'/admin\':', clientsCount);
+
+      const limit = this.configManager.getConfig('crowi', 's2cMessagingPubsub:connectionsLimitForAdmin');
+      if (limit <= clientsCount) {
+        next(new Error('Current clients for \'/admin\' exceed the limit'));
+        return;
+      }
+    }
+
+    next();
+  }
+
+  async checkConnectionLimitsForGuest(socket, next) {
+
+    if (socket.request.user == null) {
+      const clientsCount = this.connectionsCountForGuest;
+
+      logger.debug('Current clients for guests:', clientsCount);
+
+      const limit = this.configManager.getConfig('crowi', 's2cMessagingPubsub:connectionsLimitForGuest');
+      if (limit <= clientsCount) {
+        next(new Error('Current clients for guests exceed the limit'));
+        return;
+      }
+    }
+
+    next();
+  }
+
   /**
    * @see https://socket.io/docs/server-api/#socket-client
    */
   async checkConnectionLimits(socket, next) {
-
     const clients = await this.getClients(this.getDefaultSocket());
-    const adminClients = await this.getClients(this.getAdminSocket());
+    const clientsCount = clients.length;
+
+    logger.debug('Current clients for \'/\':', clientsCount);
 
-    console.log('default', clients.length);
-    console.log('admin', adminClients.length);
-    console.log('user', socket.request.user);
+    const limit = this.configManager.getConfig('crowi', 's2cMessagingPubsub:connectionsLimit');
+    if (limit <= clientsCount) {
+      next(new Error('Current clients for \'/\' exceed the limit'));
+      return;
+    }
 
     next();
-    // next(new Error('Authentication error'));
   }
 
 }