Klient Socket.io: odpowiadać na wszystkie zdarzenia jednym programem obsługi?


83

Czy możliwe jest, aby klient socket.io odpowiadał na wszystkie zdarzenia bez określania każdego zdarzenia indywidualnie?

Na przykład coś takiego (co oczywiście teraz nie działa):

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

Chcę, aby ta funkcja zwrotna była wywoływana, gdy jakiekolwiek / wszystkie zdarzenia zostaną odebrane przez kod socket.io po stronie klienta.

czy to możliwe? W jaki sposób?


Otworzyłem następujący numer dotyczący przekazywania wszystkich typów zdarzeń, dodałem
Peter Uithoven

Odpowiedzi:


25

Wygląda na to, że biblioteka socket.io przechowuje je w słowniku. W związku z tym nie myśl, że byłoby to możliwe bez modyfikacji źródła.

Ze źródła :

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


W 2019 roku chyba już tak nie jest.
Urasquirrel

82

Zaktualizowane rozwiązanie dla 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
};

Użyj w ten sposób:

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

Żadna z odpowiedzi nie zadziałała dla mnie, chociaż ta autorstwa Mathiasa Hopfa i Marosa Pixela była bliska, to jest moja dostosowana wersja.

UWAGA: to przechwytuje tylko zdarzenia niestandardowe, a nie łączy / rozłącza itp


2
Dziękuję, pomogło mi to debugować brakujące wydarzenia!
Maitreya

1
Niestety nie działa z takimi rzeczami jak „użytkownik. *” ;. Może uda mi się to wdrożyć.
C4d

Cześć, bardzo dobrze, ale byłoby pomocne, gdybyś miał kilka przykładów wyjściowych ^^ Czuję, że muszę uruchomić kod, aby zrozumieć twoją odpowiedź :)
538ROMEO

24

Wreszcie istnieje moduł o nazwie socket.io-wildcard, który umożliwia używanie symboli wieloznacznych po stronie klienta i serwera

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

Proszę bardzo ...

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

Będzie to złapać wydarzeń, takich jak connecting, connect, disconnect, reconnectingzbyt, więc dbać.


Wersja Socket.IO.js: 0.9.10, rozwój.
Kaustubh Karkare

3
Czy skończyło się to wydaniem?
hacklikecrack

9

Uwaga: ta odpowiedź jest ważna tylko dla socket.io 0.x

Możesz nadpisać socket. $ Emit

Z poniższym kodem masz dwie nowe funkcje do:

  • Złap wszystkie wydarzenia
  • Przechwytuj tylko zdarzenia, które nie są przechwytywane przez starą metodę (jest to domyślny odbiornik)
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));
});

Wszelkie porady dotyczące operacji aync przed wywołaniem mają zastosowanie. setTimeout (function () {original_ $ emit.apply (socket, ['*']. concat (args)); if (! original_ $ emit.apply (socket, arguments)) {original_ $ emit.apply (socket, [ 'default']. concat (args));}}, 2000);
Enki

Używam Socket.IO 1.3.6 i wydaje się, że nie ma socketjuż metody $
emit

W rzeczy samej. Sprawdź odpowiedź @Flion dla wersji 1.x
leszek.hanusz

7

Bieżący dokument GitHub (z kwietnia 2013 r.) Dotyczący ujawnionych zdarzeń wspomina o socket.on('anything'). Wygląda na to, że „cokolwiek” jest symbolem zastępczym nazwy wydarzenia niestandardowego, a nie faktycznym słowem kluczowym, które mogłoby wyłapać dowolne wydarzenie.

Właśnie zacząłem pracować z gniazdami internetowymi i Node.JS i od razu musiałem obsłużyć każde zdarzenie, a także dowiedzieć się, jakie zdarzenia zostały wysłane. Nie mogę uwierzyć, że tej funkcji brakuje w socket.io.


5

socket.io-client 1.7.3

W maju 2017 nie mogłem sprawić, by żadne z innych rozwiązań działało tak, jak chciałem - stworzyłem przechwytywacz, używając na Node.js wyłącznie do celów testowych:

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

Bibliografia:


3

Na stronie dotyczącej repozytorium Socket.IO toczy się długa dyskusja na ten temat . Istnieje wiele opublikowanych tam rozwiązań (np. Zastąpienie EventEmitter przez EventEmitter2). lmjabreu wydało inne rozwiązanie kilka tygodni temu: moduł npm o nazwie socket.io-wildcard, który łata zdarzenie wieloznaczne na Socket.IO (działa z obecnym Socket.IO, ~ 0.9.14).


4
Ale to tylko po stronie serwera ... jego moduł nie jest użyteczny po stronie klienta (przeglądarki)
Sander,

3

Ponieważ twoje pytanie było dość ogólne, prosząc o rozwiązanie, przedstawię to, które nie wymaga hakowania kodu, a jedynie zmianę sposobu korzystania z gniazda.

Właśnie zdecydowałem, że moja aplikacja kliencka będzie wysyłać dokładnie to samo zdarzenie, ale z innym ładunkiem.

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

A na serwerze coś w rodzaju ...

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

Nie wiem, czy używanie tego samego zdarzenia zawsze może powodować jakieś problemy, może jakieś kolizje na dużą skalę, ale to służyło moim celom.


2

Chociaż jest to stare pytanie, mam ten sam problem i rozwiązałem go za pomocą natywnego gniazda in Node.js, które ma zdarzenie .on ('data'), uruchamiane za każdym razem, gdy przychodzą jakieś dane. Oto, co zrobiłem do tej pory:

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

1

Wszystkie znalezione metody (w tym socket.io-wildcard i socketio-wildcard) nie działały dla mnie. Najwyraźniej nie ma $ emitowanego w socket.io 1.3.5 ...

Po przeczytaniu kodu socket.io załatałem następujące, które DZIAŁAły:

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

To może być rozwiązanie również dla innych. Jednak bankomat nie do końca rozumiem, dlaczego nikt inny nie ma problemów z istniejącymi „rozwiązaniami”?!? Jakieś pomysły? Może to moja stara wersja węzła (0.10.31) ...


Mogę potwierdzić, że działa i, jak zauważyłeś, jest jedynym, który działa (w tym sensie: dla mnie też). Dziękuję Ci bardzo!
znak

1

@Matthias Hopf odpowiedz

Zaktualizowana odpowiedź dla wersji 1.3.5. Wystąpił błąd z argumentami, jeśli chcesz słuchać razem starego wydarzenia i *wydarzenia.

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

0

Używam Angular 6 i pakietu npm: ngx-socket-io

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

...

constructor(private socket: Socket) { }

...

Po podłączeniu gniazda używam tego kodu, to obsługuje wszystkie zdarzenia niestandardowe ...

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.