web-dev-qa-db-fra.com

Socket.io Client: répondez à tous les événements avec un seul gestionnaire?

Est-il possible d'avoir un client socket.io qui réponde à tous les événements sans avoir à spécifier chaque événement individuellement?

Par exemple, quelque chose comme ceci (qui évidemment ne fonctionne pas pour le moment):

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

Je souhaite que cette fonction de rappel soit appelée lorsque tout/tous les événements sont reçus par le code socket.io côté client.

Est-ce possible? Comment?

68
Derick Bailey

Il semble que la bibliothèque socket.io les stocke dans un dictionnaire. En tant que tel, ne pensez pas que cela serait possible sans modifier le source.

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

Solution mise à jour pour 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
};

Utilisez comme ceci:

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

Aucune des réponses n’a fonctionné pour moi, bien que celles de Mathias Hopf et de Maros Pixel soient proches, c’est ma version ajustée.

NOTE: cela ne capture que les événements personnalisés, pas de connexion/déconnexion, etc.

58
Flion

Enfin, il existe un module appelé socket.io-wildcard qui permet d'utiliser des jokers côté client et côté serveur

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

io.use(middleware);

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

io.listen(8000);
17

Voici ...

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

Cela interceptera des événements tels que connecting, connect, disconnect, reconnecting également, donc faites attention.

11
Kaustubh Karkare

Remarque: cette réponse n'est valable que pour socket.io 0.x

Vous pouvez remplacer socket. $ Emit

Avec le code suivant, vous avez deux nouvelles fonctions:

  • Trap tous les événements
  • Ne capturer que les événements qui ne sont pas capturés par l'ancienne méthode (c'est un écouteur par défaut)
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));
});
9
leszek.hanusz

Le document actuel (avril 2013) la documentation GitHub sur les événements exposés mentionne une socket.on('anything'). Il semble que "tout" soit un espace réservé pour un nom d'événement personnalisé, et non un mot clé réel pouvant intercepter un événement.

Je viens juste de commencer à travailler avec les sockets Web et Node.JS, et j’ai immédiatement eu besoin de gérer tout événement, ainsi que de savoir quels événements avaient été envoyés. Je ne peux pas croire que cette fonctionnalité manque dans socket.io.

7
Dan Dascalescu

socket.io-client 1.7.3

En mai 2017, aucune autre solution ne fonctionnait exactement comme je le souhaitais - fabriquait un intercepteur, utilisé sur Node.js uniquement à des fins de test:

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

Références:

5
Fabiano Soriani

Il y a une longue discussion à ce sujet se passe sur la page des problèmes du référentiel Socket.IO. Diverses solutions y sont publiées (par exemple, remplacer EventEmitter avec EventEmitter2). lmjabreu a publié une autre solution il y a quelques semaines: un module npm appelé socket.io-wildcard qui corrige un événement générique sur Socket.IO (fonctionne avec le Socket.IO actuel, ~ 0.9.14).

3
sffc

Parce que votre question était assez générale en demandant une solution, je vais lancer celle qui ne nécessite pas de piratage du code, juste un changement dans la façon dont vous utilisez le socket.

Je viens de décider que mon application client envoie le même événement, mais avec une charge utile différente.

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

Et sur le serveur, quelque chose comme ...

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

Je ne sais pas si le fait de toujours utiliser le même événement pourrait causer des problèmes, peut-être des collisions à une échelle quelconque, mais cela a très bien servi mes objectifs.

3
Dan

@Mathias Hopf réponse

Réponse mise à jour pour v1.3.5. Il y avait un bug avec args, si vous voulez écouter l'ancien événement et l'événement * ensemble.

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
Maros Pixel

Toutes les méthodes que j'ai trouvées (y compris socket.io-wildcard et socketio-wildcard) ne fonctionnaient pas pour moi. Apparemment, il n'y a pas de $ emit dans socket.io 1.3.5 ...

Après avoir lu le code socket.io, j’ai corrigé ce qui suit DID:

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

Cela pourrait être une solution pour les autres aussi. Cependant, je ne comprends pas très bien pourquoi personne ne semble avoir de problèmes avec les "solutions" existantes?!? Des idées? C'est peut-être mon ancienne version de nœud (0.10.31) ...

1
Matthias Hopf

J'utilise Angular 6 et le paquet npm: ngx-socket-io

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

...

constructor(private socket: Socket) { }

...

Après avoir connecté le socket, j'utilise ce code, il gère tous les événements personnalisés ...

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}]`);
  }
});
0
Alejandro