Zaz
Zaz

Reputation: 48769

Add listener to Object prototype

I'm running a WebSocket server with ws, and am trying to split incoming messages based on whether they are JSON or not.

function determineJSON(m) {
    try         { return ['json', JSON.parse(m)] }
    catch (err) { return ['not-json', m] }
}

wss.on('connection', ws => {
    ws.on('message', m => {
        // Emit to 'json' and 'not-json' as appropriate
        if (ws.listenerCount('json') + ws.listenerCount('not-json') > 0) {
            ws.emit(...determineJSON(m))
        }
    })
    .on('json', j => { ... })
    .on('not-json', m => { ... })
})

The code works great, but I was wondering how I could add the .on('message', ...) listener to the WS class, so that all new WS objects would have it. I tried WS.prototype.on('message', ...), but that didn't seem to do anything.

Upvotes: 0

Views: 111

Answers (2)

Anton Kononenko
Anton Kononenko

Reputation: 493

So actually you want creating instances of WS with predefined state?

For that purpose I would suggest you just to create a factory which would handle it for you.

WsFactory.create = function () {
    var ws = new WS(); //or whatever you use for creating
    ws.on(...);
    return ws;
}

You would avoid mutating prototypes, and would get what you want to have.

Upvotes: 1

Ivan Drinchev
Ivan Drinchev

Reputation: 19581

Well I'm not a big fan of modifying the prototype, so you can do something like :

function determineJSON(m) {
    try         { return ['json', JSON.parse(m)] }
    catch (err) { return ['not-json', m] }
}

function decorateWS(ws) {
    return ws.on('message', m => {
        // Emit to 'json' and 'not-json' as appropriate
        if (ws.listenerCount('json') + ws.listenerCount('not-json') > 0) {
            ws.emit(...determineJSON(m))
        }
    })
}

wss.on('connection', ws => {
    decorateWS(ws).on('json', j => { ... })
                  .on('not-json', m => { ... })
})

Anyway if you want to modify the class itself you will probably need to do something like :

let origConstructor = ws.prototype.constructor;
WS.prototype.constructor = () => {
   origConstructor.apply( this, arguments );
   const ws = this;
   this.on('message', m => {
       // Emit to 'json' and 'not-json' as appropriate
       if (ws.listenerCount('json') + ws.listenerCount('not-json') > 0) {
           ws.emit(...determineJSON(m))
       }  
     })
}

In any case I think this might have side effects. So the decorate approach looks far better and maintainable.

Upvotes: 0

Related Questions