2012-05-01 18 views
60

¿Es posible que un cliente socket.io responda a todos los eventos sin tener que especificar cada evento individualmente?Socket.io Cliente: ¿responde a todos los eventos con un solo controlador?

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 esta función de devolución de llamada que se llamará cuando cualquiera/todos los eventos son recibidos por la toma del lado del cliente. código io

¿Esto es posible? ¿Cómo?

+0

abrí la El siguiente número sobre el reenvío de todos los tipos de eventos, también he estado agregando las soluciones que encontré: https://github.com/Automattic/socket.io/issues/1715 –

Respuesta

19

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

De 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; 
    }; 
+3

también encontró esto: http: // stackoverflow.com/questions/8832414/overriding-socket-ios-emit-and-on/8838225 –

10

Aquí 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, reconnecting demasiado, así que tenga cuidado.

+0

Socket.IO.js build: 0.9.10, desarrollo. –

+3

¿Esto terminó en un lanzamiento? – hacklikecrack

7

La corriente (abril de 2013) GitHub doc on exposed events menciona un 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 atrapará cualquier evento.

Acabo de empezar 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 no se encuentre en socket.io.

3

Hay a long discussion about this topic en la página de problema del repositorio de Socket.IO. Existe una variedad de soluciones publicadas allí (por ejemplo, reemplazando a EventEmitter con EventEmitter2). lmjabreu lanzó otra solución hace un par de semanas: un módulo npm llamado socket.io-wildcard que parchea en un evento comodín en Socket.IO (funciona con el Socket.IO actual, ~ 0.9.14).

+3

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

9

Nota: esta respuesta sólo es válida para socket.io 0.x

Puede anular zócalo $ emiten

Con el siguiente código tiene dos nuevas funciones a:.

  • Trap todos los eventos
  • Trampa solo los 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)); 
}); 
+0

Cualquier consejo sobre una operación aync antes de llamar se aplica. \t setTimeout (function() { \t \t \t \t original_ $ emit.apply (zócalo, [ '*'] concat (args));.! \t \t \t \t si (original_ $ emit.apply (zócalo, argumentos)) { \t \t \t \t \t original_ $ emit.apply) (socket, [ 'default'] concat (args.); \t \t \t \t} \t \t \t}, 2000); – Enki

+0

Estoy usando Socket.IO 1.3.6 y no parece haber un método $ emitir en 'socket' más – raimohanska

+0

De hecho. Compruebe @Flion respuesta para las versiones 1.x –

1

Todos los métodos que he encontrado (incluyendo socket.io-comodín y socketio-comodín) no funcionó para mí. Aparentemente no hay $ emiten en socket.io 1.3.5 ...

Después de leer el socket.código io, que remendó los siguientes elementos 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 
}; 

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

+0

Puedo confirmar que funciona y, como ha observado, es el único que funciona (en el sentido: para mí también). ¡Muchas gracias! – mark

3

Como tu pregunta fue bastante general al pedir una solución, lanzaré esta que no requiere hackear el código, solo un cambio en la forma de usarlo la toma.

Acabo de decidir que mi aplicación cliente envíe exactamente el mismo evento, pero con una carga diferente.

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

Y en el servidor, algo así como ...

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

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

1

@Matthias Hopf responder

respuesta actualizada para la v1.3.5. Hubo un error con args, si quieres escuchar el evento viejo 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 
}; 
50

solución actualizada para socket.io-cliente 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 
}; 

uso como esto:

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

Ninguna de las respuestas trabajó para mí, aunque la de Mathias Hopf y Maros Pixel se acercaron, esta es mi versión ajustada.

NOTA: esto sólo atrapa eventos personalizados, no de conexión/desconexión, etc.

+2

¡Gracias, esto me ayudó a depurar eventos perdidos! – Maitreya

+2

Esto funcionó perfectamente, ¡gracias! – Jonathan

+1

Lamentablemente, no funciona con cosas como 'usuario. *' ;. Quizás pueda implementarlo. – C4u

12

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

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

io.use(middleware); 

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

io.listen(8000); 
+0

funciona a la perfección – tinybyte

2

socket.io-client 1.7.3

A partir de mayo de 2017 no se pudo hacer ninguna de las otras soluciones funcionan bastante cómo quería - hice un interceptor, usando al Node.js para propósitos 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:

Cuestiones relacionadas