92

Is it possible to have a socket.io client respond to all events without to have specify each event individually?

For example, something like this (which obviously doesn't work right now):

var socket = io.connect("http://myserver");

socket.on("*", function(){
  // listen to any and all events that are emitted from the
  // socket.io back-end server, and handle them here.

  // is this possible? how can i do this?
});

I want this callback function to be called when any / all events are received by the client-side socket.io code.

Is this possible? How?

Derick Bailey
  • 72,004
  • 22
  • 206
  • 219
  • I opened the following issue on forwarding all event types, I've also been adding the solutions I found: https://github.com/Automattic/socket.io/issues/1715 – Peter Uithoven Aug 27 '14 at 19:41

15 Answers15

89

Updated solution for socket.io-client 1.3.7

var onevent = socket.onevent;
socket.onevent = function (packet) {
    var args = packet.data || [];
    onevent.call (this, packet);    // original call
    packet.data = ["*"].concat(args);
    onevent.call(this, packet);      // additional call to catch-all
};

Use like this:

socket.on("*",function(event,data) {
    console.log(event);
    console.log(data);
});

None of the answers worked for me, though the one of Mathias Hopf and Maros Pixel came close, this is my adjusted version.

NOTE: this only catches custom events, not connect/disconnect etc

Flion
  • 10,468
  • 13
  • 48
  • 68
  • 2
    Thank you, this helped me debug missing events! – Maitreya May 19 '16 at 08:02
  • 1
    Unfortunately not working with things like 'user.*';. Maybe I can manage to implement it. – C4d Mar 16 '17 at 16:54
  • Hi, very good, but it could be helpful if you could have some output examples ^^ I feel like I need to run the code to understand your answer :) – TOPKAT Oct 03 '19 at 16:47
26

It looks like the socket.io library stores these in a dictionary. As such, don't think this would be possible without modifying the source.

From source:

EventEmitter.prototype.on = function (name, fn) {
    if (!this.$events) {
      this.$events = {};
    }

    if (!this.$events[name]) {
      this.$events[name] = fn;
    } else if (io.util.isArray(this.$events[name])) {
      this.$events[name].push(fn);
    } else {
      this.$events[name] = [this.$events[name], fn];
    }

    return this;
  };
lukiffer
  • 11,025
  • 8
  • 46
  • 70
25

Finally, there is a module called socket.io-wildcard which allows using wildcards on client and server side

var io         = require('socket.io')();
var middleware = require('socketio-wildcard')();

io.use(middleware);

io.on('connection', function(socket) {
  socket.on('*', function(){ /* … */ });
});

io.listen(8000);
Marian Klühspies
  • 15,824
  • 16
  • 93
  • 136
11

Here you go ...

var socket = io.connect();
var globalEvent = "*";
socket.$emit = function (name) {
    if(!this.$events) return false;
    for(var i=0;i<2;++i){
        if(i==0 && name==globalEvent) continue;
        var args = Array.prototype.slice.call(arguments, 1-i);
        var handler = this.$events[i==0?name:globalEvent];
        if(!handler) handler = [];
        if ('function' == typeof handler) handler.apply(this, args);
        else if (io.util.isArray(handler)) {
            var listeners = handler.slice();
            for (var i=0, l=listeners.length; i<l; i++)
                listeners[i].apply(this, args);
        } else return false;
    }
    return true;
};
socket.on(globalEvent,function(event){
    var args = Array.prototype.slice.call(arguments, 1);
    console.log("Global Event = "+event+"; Arguments = "+JSON.stringify(args));
});

This will catch events like connecting, connect, disconnect, reconnecting too, so do take care.

Kaustubh Karkare
  • 1,083
  • 9
  • 25
9

Note: this answer is only valid for socket.io 0.x

You can override socket.$emit

With the following code you have two new functions to:

  • Trap all events
  • Trap only events which are not trapped by the old method (it is a default listener)
var original_$emit = socket.$emit;
socket.$emit = function() {
    var args = Array.prototype.slice.call(arguments);
    original_$emit.apply(socket, ['*'].concat(args));
    if(!original_$emit.apply(socket, arguments)) {
        original_$emit.apply(socket, ['default'].concat(args));
    }
}

socket.on('default',function(event, data) {
    console.log('Event not trapped: ' + event + ' - data:' + JSON.stringify(data));
});

socket.on('*',function(event, data) {
    console.log('Event received: ' + event + ' - data:' + JSON.stringify(data));
});
leszek.hanusz
  • 5,152
  • 2
  • 38
  • 56
  • Any advice on an aync operation before calling apply. setTimeout(function() { original_$emit.apply(socket, ['*'].concat(args)); if(!original_$emit.apply(socket, arguments)) { original_$emit.apply(socket, ['default'].concat(args)); } }, 2000); – Enki Mar 15 '14 at 19:58
  • I'm using Socket.IO 1.3.6 and there doesn't seem to be a $emit method in `socket` anymore – raimohanska Sep 28 '15 at 13:47
  • Indeed. Check @Flion answer for 1.x versions – leszek.hanusz Aug 18 '16 at 10:47
9

As it is in v3.0 documentation:

socket.onAny((event, ...args) => {
  console.log(`got ${event}`);
});
Carlos Oliveira
  • 846
  • 10
  • 23
7

The current (Apr 2013) GitHub doc on exposed events mentions a socket.on('anything'). It appears that 'anything' is a placeholder for a custom event name, not an actual keyword that would catch any event.

I've just started working with web sockets and Node.JS, and immediately had a need to handle any event, as well as to discover what events were sent. Can't quite believe this functionality is missing from socket.io.

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
6

socket.io-client 1.7.3

As of May 2017 couldn't make any of the other solutions work quite how i wanted - made an interceptor, using at Node.js for testing purposes only:

var socket1 = require('socket.io-client')(socketUrl)
socket1.on('connect', function () {
  console.log('socket1 did connect!')
  var oldOnevent = socket1.onevent
  socket1.onevent = function (packet) {
    if (packet.data) {
      console.log('>>>', {name: packet.data[0], payload: packet.data[1]})
    }
    oldOnevent.apply(socket1, arguments)
  }
})

References:

Fabiano Soriani
  • 8,182
  • 9
  • 43
  • 59
4

Because your question was pretty general in asking for a solution, I'll pitch this one that requires no hacking the code, just a change in how you use the socket.

I just decided to have my client app send the exact same event, but with a different payload.

socket.emit("ev", { "name" : "miscEvent1"} );
socket.emit("ev", { "name" : "miscEvent2"} );

And on the server, something like...

socket.on("ev", function(eventPayload) {
   myGenericHandler(eventPayload.name);
});

I don't know if always using the same event could cause any issues, maybe collisions of some kind at scale, but this served my purposes just fine.

Dan
  • 6,022
  • 3
  • 20
  • 28
3

There is a long discussion about this topic going on at the Socket.IO repository issue page. There are a variety of solutions posted there (e.g., overriding EventEmitter with EventEmitter2). lmjabreu released another solution a couple weeks ago: a npm module called socket.io-wildcard that patches in a wildcard event onto Socket.IO (works with the current Socket.IO, ~0.9.14).

sffc
  • 6,186
  • 3
  • 44
  • 68
2

Even though this is a old question, I have the same problem and solved using the native socket in Node.js, which has a event of .on('data'), fired everytime some data comes. So this is what I've done so far:

const net = require('net')

const server = net.createServer((socket) => {
    // 'connection' listener.
    console.log('client connected')

    // The stuff I was looking for
    socket.on('data', (data) => {
        console.log(data.toString())
    })

    socket.on('end', () => {
        console.log('client disconnected')
    })
})

server.on('error', (err) => {
    throw err;
})

server.listen(8124, () => {
    console.log('server bound');
})
m4el
  • 455
  • 1
  • 4
  • 14
1

All methods I found (including socket.io-wildcard and socketio-wildcard) didn't work for me. Apparently there is no $emit in socket.io 1.3.5...

After reading socket.io code, I patched up the following which DID work:

var Emitter = require('events').EventEmitter;
var emit = Emitter.prototype.emit;
[...]
var onevent = socket.onevent;
socket.onevent = function (packet) {
    var args = ["*"].concat (packet.data || []);
    onevent.call (this, packet);    // original call
    emit.apply   (this, args);      // additional call to catch-all
};

This might be a solution for others as well. However, ATM I don't exactly understand why nobody else seems to have issues with the existing "solutions"?!? Any ideas? Maybe it's my old node version (0.10.31)...

  • I can confirm it works and, as you observed, is the only one which works (in the sense: for me too). Thank you very much! – mark May 21 '15 at 20:20
1

@Matthias Hopf answer

Updated answer for v1.3.5. There was a bug with args, if you wanna listen on old event and * event together.

var Emitter = require('events').EventEmitter;
var emit = Emitter.prototype.emit;
// [...]
var onevent = socket.onevent;
socket.onevent = function (packet) {
    var args = packet.data || [];
    onevent.call (this, packet);    // original call
    emit.apply   (this, ["*"].concat(args));      // additional call to catch-all
};
1

In v4, Socket.IO has Catch-all listeners. For example:

socket.prependAny(() => {
   console.log("This will be fired first");
});
Cees Jol
  • 26
  • 1
  • 2
  • Your answer could be improved with additional supporting information. Please [edit](https://stackoverflow.com/posts/72517845/edit) to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the [help center](https://stackoverflow.com/help/how-to-answer). – Ethan Jun 07 '22 at 20:30
0

I'm using Angular 6 and the npm package: ngx-socket-io

import { Socket } from "ngx-socket-io";

...

constructor(private socket: Socket) { }

...

After connect the socket, I use this code, this is handling all custom events...

const onevent = this.socket.ioSocket.onevent;
this.socket.ioSocket.onevent = function (packet: any) {
  const args = packet.data || [];
  onevent.call(this, packet);    // original call
  packet.data = ["*"].concat(args);
  onevent.call(this, packet);      // additional call to catch-all
};
this.socket.on("*", (eventName: string, data: any) => {
  if (typeof data === 'object') {
    console.log(`socket.io event: [${eventName}] -> data: [${JSON.stringify(data)}]`);
  } else {
    console.log(`socket.io event: [${eventName}] -> data: [${data}]`);
  }
});
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Alejandro
  • 134
  • 2
  • 5