UNPKG

vue-express-mongo-boilerplate

Version:

Express NodeJS application server boilerplate with Mongo and VueJS

224 lines (188 loc) 5.74 kB
"use strict"; let logger = require("./logger"); let config = require("../config"); let path = require("path"); let fs = require("fs"); let http = require("http"); let _ = require("lodash"); let cookieParser = require("cookie-parser"); let passport = require("passport"); let socketio = require("socket.io"); let session = require("express-session"); let MongoStore = require("connect-mongo")(session); let Services; // circular references let self = { /** * IO server instance * We will assign it in `init` */ IO: null, /** * Mongo store instance. * We will assign it in `init` */ mongoStore: null, /** * IO namespaces * @type {Object} */ namespaces: {}, /** * List of logged in online users/sockets * @type {Array} */ userSockets: [], /** * Init Socket.IO module and load socket handlers * from applogic * * @param {Object} app Express App * @param {Object} db MongoDB connection */ init(app, db) { // Create a MongoDB storage object self.mongoStore = new MongoStore({ mongooseConnection: db.connection, collection: config.sessions.collection, autoReconnect: true }); // Create a new HTTP server let server = http.createServer(app); // Create a new Socket.io server let IO = socketio(server); app.io = self; self.IO = IO; // Add common handler to the root namespace self.initNameSpace("/", IO, self.mongoStore); IO.on("connection", function (socket) { socket.on("welcome", function(msg) { logger.info("Incoming welcome message from " + socket.request.user.username + ":", msg); }); }); let services = require("./services"); services.registerSockets(IO, self); return server; }, /** * Create a new Socket.IO namespace * * @param {any} ns name of namespace * @param {any} role required role for namespace * @returns */ addNameSpace(ns, role) { let io = self.namespaces[ns]; if (io == null) { io = self.IO.of(ns); self.initNameSpace(ns, io, self.mongoStore, role); } return io; }, /** * Initialize IO namespace. Apply authentication middleware * * @param {String} ns Name of namespace * @param {Object} io IO instance * @param {Object} mongoStore Mongo Session store * @param {Object} roleRequired required role */ initNameSpace(ns, io, mongoStore, roleRequired) { // Intercept Socket.io's handshake request io.use(function (socket, next) { // Use the 'cookie-parser' module to parse the request cookies cookieParser(config.sessionSecret)(socket.request, {}, function (err) { // Get the session id from the request cookies let sessionId = socket.request.signedCookies ? socket.request.signedCookies[config.sessions.name] : undefined; if (!sessionId) { logger.warn("sessionId was not found in socket.request"); return next(new Error("sessionId was not found in socket.request"), false); } // Use the mongoStorage instance to get the Express session information mongoStore.get(sessionId, function (err, session) { if (err) return next(err, false); if (!session) return next(new Error("session was not found for " + sessionId), false); // Set the Socket.io session information socket.request.session = session; // Set the socketID to session session.socket = socket.id; mongoStore.set(sessionId, session); // Use Passport to populate the user details passport.initialize()(socket.request, {}, function () { passport.session()(socket.request, {}, function () { if (socket.request.user) { let user = socket.request.user; if (roleRequired) { if (user.roles && user.roles.indexOf(roleRequired) !== -1) next(null, true); else { logger.warn(`Websocket user has no access to this namespace '${ns}'!`, user.username); next(new Error(`You have NO access to this namespace '${ns}'!`), false); } } else next(null, true); } else { logger.warn("Websocket user is not authenticated!"); next(new Error("User is not authenticated! Please login first!"), false); } }); }); }); }); }); // Add an event listener to the 'connection' event io.on("connection", function (socket) { if (!Services) Services = require("./services"); Services.emit("socket:connect", socket); self.addOnlineUser(socket); logger.debug("WS client connected to namespace " + (io.name || "root") + "! User: " + socket.request.user.username); socket.on("disconnect", function() { Services.emit("socket:connect", socket); self.removeSocket(socket); logger.debug("WS client disconnected from namespace " + (io.name || "root") + "!"); }); }); self.namespaces[ns] = io; }, /** * Emit a message to a namespace * * @param {any} namespace * @param {any} command * @param {any} data * @returns */ nsEmit(namespace, command, data) { if (self.namespaces[namespace]) { self.namespaces[namespace].emit(command, data); return true; } }, /** * Add a socket to the online users list * * @param {any} socket */ addOnlineUser(socket) { self.removeOnlineUser(socket); self.userSockets.push(socket); }, /** * Remove a socket from the online users * * @param {any} socket */ removeSocket(socket) { _.remove(self.userSockets, function(s) { return s == socket; }); }, /** * Remove sockets of user from the online users * * @param {any} socket */ removeOnlineUser(socket) { _.remove(self.userSockets, function(s) { return s.request.user._id == socket.request.user._id; }); } }; module.exports = self;