Cliente Socket.io: ¿responder a todos los eventos con un solo controlador?


82

¿Es posible que un cliente socket.io responda a todos los eventos sin tener que especificar cada evento individualmente?

Por ejemplo, algo como esto (que obviamente no funciona en este momento):

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?
});

Quiero que se llame a esta función de devolución de llamada cuando el código socket.io del lado del cliente reciba cualquiera o todos los eventos.

es posible? ¿Cómo?


Abrí el siguiente problema sobre el reenvío de todos los tipos de eventos, también he estado agregando las soluciones que encontré: github.com/Automattic/socket.io/issues/1715
Peter Uithoven

Respuestas:


25

Parece que la biblioteca socket.io los almacena en un diccionario. Como tal, no crea que esto sería posible sin modificar la fuente.

De la fuente :

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;
  };


En 2019, creo que ya no es así.
Urasquirrel

82

Solución actualizada para 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 así:

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

Ninguna de las respuestas me funcionó, aunque la de Mathias Hopf y Maros Pixel se acercó, esta es mi versión ajustada.

NOTA: esto solo captura eventos personalizados, no se conecta / desconecta, etc.


2
Gracias, esto me ayudó a depurar eventos faltantes.
Maitreya

1
Desafortunadamente, no funciona con cosas como 'usuario. *' ;. Tal vez pueda lograr implementarlo.
C4d

Hola, muy bien, pero podría ser útil si pudiera tener algunos ejemplos de salida ^^ Siento que necesito ejecutar el código para entender su respuesta :)
538ROMEO

24

Finalmente , hay un módulo llamado socket.io-wildcard que permite usar comodines en el lado del cliente y del servidor

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

io.use(middleware);

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

io.listen(8000);

11

Aqui tienes ...

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));
});

Esto cogerá eventos como connecting, connect, disconnect, reconnectingtambién, así que cuidar su toma.


Socket.IO.js compilación: 0.9.10, desarrollo.
Kaustubh Karkare

3
¿Terminó esto en un lanzamiento?
hacklikecrack

9

Nota: esta respuesta solo es válida para socket.io 0.x

Puede anular socket. $ Emit

Con el siguiente código tienes dos nuevas funciones para:

  • Atrapa todos los eventos
  • Capture solo eventos que no están atrapados por el método anterior (es un oyente predeterminado)
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));
});

Se aplica cualquier consejo sobre una operación aync antes de llamar. setTimeout (función () {original_ $ emit.apply (socket, ['*']. concat (args)); if (! original_ $ emit.apply (socket, argumentos)) {original_ $ emit.apply (socket, [ 'predeterminado']. concat (args));}}, 2000);
Enki

Estoy usando Socket.IO 1.3.6 y no parece ser un método emiten en $ socketmás
raimohanska

En efecto. Verifique la respuesta de @Flion para versiones 1.x
leszek.hanusz

7

El documento de GitHub actual (abril de 2013) sobre eventos expuestos menciona a socket.on('anything'). Parece que "cualquier cosa" es un marcador de posición para un nombre de evento personalizado, no una palabra clave real que capturaría cualquier evento.

Acabo de comenzar a trabajar con sockets web y Node.JS, e inmediatamente tuve la necesidad de manejar cualquier evento, así como descubrir qué eventos se enviaron. No puedo creer que esta funcionalidad falte en socket.io.


5

socket.io-client 1.7.3

A partir de mayo de 2017, no podía hacer que ninguna de las otras soluciones funcionara como quería: hice un interceptor, utilizándolo en Node.js solo con fines de prueba:

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)
  }
})

Referencias:


3

Hay una larga discusión sobre este tema en la página de problemas del repositorio de Socket.IO. Hay una variedad de soluciones publicadas allí (por ejemplo, anular EventEmitter con EventEmitter2). lmjabreu lanzó otra solución hace un par de semanas: un módulo npm llamado socket.io-wildcard que se parchea en un evento comodín en Socket.IO (funciona con el Socket.IO actual, ~ 0.9.14).


4
Pero eso es solo del lado del servidor ... su módulo no se puede usar en el lado del cliente (navegador)
Sander

3

Debido a que su pregunta fue bastante general al pedir una solución, presentaré esta que no requiere piratear el código, solo un cambio en la forma en que usa el socket.

Decidí que mi aplicación cliente enviara exactamente el mismo evento, pero con una carga útil diferente.

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

Y en el servidor, algo como ...

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

No sé si usar siempre el mismo evento podría causar algún problema, tal vez colisiones de algún tipo a escala, pero esto cumplió mis propósitos muy bien.


1

Todos los métodos que encontré (incluidos socket.io-wildcard y socketio-wildcard) no funcionaron para mí. Aparentemente no hay $ emit en socket.io 1.3.5 ...

Después de leer el código socket.io, reparé lo siguiente que funcionó:

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
};

Esta también podría ser una solución para otros. Sin embargo, ATM no entiendo exactamente por qué nadie más parece tener problemas con las "soluciones" existentes. ¿Algunas ideas? Tal vez sea mi antigua versión de nodo (0.10.31) ...


Puedo confirmar que funciona y, como usted observó, es el único que funciona (en el sentido: para mí también). ¡Muchas gracias!
marcar

1

@Matthias Hopf respuesta

Respuesta actualizada para v1.3.5. Hubo un error con los argumentos, si quieres escuchar el evento antiguo y el *evento juntos.

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

Aunque esta es una pregunta antigua, tengo el mismo problema y lo resolví usando el socket nativo Node.js, que tiene un evento de .on ('datos'), que se activa cada vez que llegan algunos datos. Así que esto es lo que he hecho hasta ahora:

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');
})

0

Estoy usando Angular 6 y el paquete npm : ngx-socket-io

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

...

constructor(private socket: Socket) { }

...

Después de conectar el enchufe, uso este código, este está manejando todos los eventos personalizados ...

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}]`);
  }
});
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.