socketcluster icon indicating copy to clipboard operation
socketcluster copied to clipboard

How to organize large numbers of event handlers

Open maxwellhaydn opened this issue 5 years ago • 1 comments

When you start handling many different types of events, the code in worker.js can get a little unwieldy:

scServer.on('connection', socket => {
    socket.on('foo1', (data, res) => { ... });
    socket.on('foo2', (data, res) => { ... });
    socket.on('foo3', (data, res) => { ... });
    socket.on('bar1', (data, res) => { ... });
    socket.on('bar2', (data, res) => { ... });
    ...
});

Is there a recommended/built-in way to split these handlers into their own modules?

If not, it would be nice to add a module that does something like express.Router does for Express routes. For example:

// foo-handlers.js
const eventManager = require('socketcluster/event-manager');

eventManager.on('foo1', (data, res) => { ... });
eventManager.on('foo2', (data, res) => { ... });
eventManager.on('foo3', (data, res) => { ... });

module.exports = eventManager;

// bar-handlers.js
const eventManager = require('socketcluster/event-manager');

eventManager.on('bar1', (data, res) => { ... });
eventManager.on('bar2', (data, res) => { ... });

module.exports = eventManager;

// worker.js
const foo = require('./foo-handlers'),
    bar = require('./bar-handlers');

scServer.on('connection', socket => {
    socket.register(foo);
    socket.register(bar);
});

I hacked together a rough attempt at this:

class SCEventManager {
    constructor() {
        this.handlers = {};
    }

    on(eventName, callback) {
        this.handlers[eventName] = callback;
    }

    register(socket) {
        Object.keys(this.handlers).forEach(eventName => {
            socket.on(eventName, this.handlers[eventName]);
        });
    }
}

module.exports = () => new SCEventManager();

But you have to call foo.register(socket) instead of socket.register(foo):

// foo-handlers.js
const eventManager = require('sc-event-manager')();

eventManager.on('foo1', (data, res) => { ... });
eventManager.on('foo2', (data, res) => { ... });
eventManager.on('foo3', (data, res) => { ... });

module.exports = eventManager;

// worker.js

const foo = require('./foo-handlers');

scServer.on('connection', socket => {
    foo.register(socket);
});

There are probably other issues with this design; it would be nice if there were something integrated with Socketcluster that did this. Also, express.Router provides other neat features like per-module routing prefixes and middleware that might be useful in such a feature.

maxwellhaydn avatar Feb 09 '19 20:02 maxwellhaydn

@maxwellhaydn that sound like a good solution to help organize handlers but I think it's better as a separate module because SC shouldn't be too opinionated about code organization (any more than it already is). If you've published such a module to npm, feel free to share it with the community here.

jondubois avatar Feb 26 '19 21:02 jondubois