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?
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;
};
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.
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);
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.
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:
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));
});
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.
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:
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).
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.
@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
};
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) ...
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}]`);
}
});