Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combine sockets and express when using express middleware?

Is there a way to get the socket of a request inside of an express middleware?

ie:

import express from 'express';
import io from 'socket.io';

const app = express();

// combine app and io somehow ...

// When client makes a GET request to '/emit/to/self', that client's socket will recieve the 'hello:world' message.
app.get('/emit/to/self', (req, res) => {
  req.socket.emit('hello:world', { ... });
  res.send('You just triggered your own socket!')
})

The idea being that express middleware has a req.socket property that references the connected socket from the same client. This would allow for some more complex use cases, such as:

app.post('/image/create', (req, res) => {
  createExpensiveImage({
    onProgress: (progress) => { req.socket.emit('image:progress', { progress }) },
  });
})

The client would have an accurate progress bar of the image they just requested to create through the API.

like image 409
Justin Schultz Avatar asked Feb 21 '17 23:02

Justin Schultz


1 Answers

Here's a way to connect socket.io and express. It uses express-session to create a secure session object for a given client. Then, when a socket.io connection happens, it gets the session for that client and stores the socket.id in the session.

Then, you are positioned to either get the socketID from the session from within an express route handler so you can emit to that client over socket.io. Or, you can get session data from that user when you are in a socket.io message handler. You can go either way. Here's the basic code:

const express = require('express');
const app = express();
const server = app.listen(80);
const io = require('socket.io')(server);
const expsession = require('express-session');
const path = require('path');

// initialize session middleware
const sessionMiddleware = expsession({
  secret: 'random secret',
  saveUninitialized: true,
  resave: true
});

// hook up session for express routes
app.use(sessionMiddleware);

// hook up the session for socket.io connections
io.use(function(socket, next) {
    sessionMiddleware(socket.request, socket.request.res, next);
});

// when a socket.io connect connects, get the session and store the id in it
io.on('connection', function(socket) {
    // socket.handshake.headers
    console.log(`socket.io connected: ${socket.id}`);
    // save socket.io socket in the session
    console.log("session at socket.io connection:\n", socket.request.session);
    socket.request.session.socketio = socket.id;
    socket.request.session.save();
});

// general middleware to demo an increasing, per-client value in the session
app.use(function(req, res, next) {
    // req.session
    const session = req.session;
    if (!session.cntr) session.cntr = 0;
    ++session.cntr;
    next();
});

// route handler to serve up default page    
app.get("/", function(req, res) {
    const session = req.session;
    console.log("\n\npage load\n---------------------------\n");
    console.log("session:\n", session);
    res.sendFile(path.join(__dirname, "socket-io-session.html"));
});

let cntr = 1;

// test route to show using socket.io .emit() from an express route
app.get("/api/test", function(req, res) {
    const session = req.session;
    io.sockets.connected[session.socketio].emit('show', cntr++);
    res.json({greeting: "hello"});
});
like image 158
jfriend00 Avatar answered Oct 06 '22 21:10

jfriend00