web-dev-qa-db-ja.com

Socket.ioクライアント:1つのハンドラーですべてのイベントに応答しますか?

各イベントを個別に指定せずに、socket.ioクライアントをすべてのイベントに応答させることは可能ですか?

たとえば、次のようなものです(明らかに現在は動作しません):

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

クライアント側のsocket.ioコードがすべてのイベントを受信したときに、このコールバック関数が呼び出されるようにします。

これは可能ですか?どうやって?

75
Derick Bailey

Socket.ioライブラリはこれらを辞書に保存しているようです。そのため、ソースを変更せずにこれが可能になるとは思わないでください。

ソース から:

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

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

次のように使用します。

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

Mathias HopfとMaros Pixelのいずれかが近づいていましたが、答えは私にはうまくいきませんでしたが、これは私の調整されたバージョンです。

注:これはカスタムイベントのみをキャッチし、接続/切断などはキャッチしません

71
Flion

最後にsocket.io-wildcard と呼ばれるモジュールがあり、クライアント側とサーバー側でワイルドカードを使用できます

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

io.use(middleware);

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

io.listen(8000);
18

どうぞ ...

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

これは、connectingconnectdisconnectreconnectingなどのイベントもキャッチするため、注意してください。

11

注:この回答はsocket.io 0.xでのみ有効です

socket。$ emitをオーバーライドできます

次のコードを使用すると、次の2つの新しい関数を使用できます。

  • すべてのイベントをトラップする
  • 古いメソッドによってトラップされないイベントのみをトラップします(デフォルトのリスナーです)
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

現在(2013年4月) 公開されたイベントに関するGitHubドキュメントsocket.on('anything')に言及しています。 'anything'はカスタムイベント名のプレースホルダーであり、イベントをキャッチする実際のキーワードではないようです。

WebソケットとNode.JSを使い始めたばかりで、すぐにイベントを処理し、送信されたイベントを検出する必要がありました。この機能がsocket.ioに欠けているとは信じられません。

7
Dan Dascalescu

socket.io-client 1.7.3

2017年5月の時点で、他のソリューションを思い通りに動作させることができませんでした-Node.jsでテスト目的のみで使用するインターセプターを作成しました:

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

参照:

5
Fabiano Soriani

Socket.IOリポジトリの問題ページで このトピックに関する長い議論 が進行中です。そこにはさまざまなソリューションが投稿されています(たとえば、EventEmitterをEventEmitter2でオーバーライドする)。 lmjabreuは数週間前に別のソリューションをリリースしました: socket.io-wildcard と呼ばれるnpmモジュールは、Socket.IOにワイルドカードイベントでパッチを当てます(現在のSocket.IOで動作します、〜0.9.14)。

3
sffc

あなたの質問は解決策を求めるのにかなり一般的だったので、コードのハッキングを必要とせず、ソケットの使用方法を変更するだけでよいこの問題を提案します。

クライアントアプリにまったく同じイベントを送信することにしましたが、ペイロードは異なります。

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

そして、サーバー上で、次のような...

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

常に同じイベントを使用すると問題が発生する可能性があるかどうかはわかりませんが、大規模な何らかの衝突が発生する可能性がありますが、これは私の目的をうまく果たしました。

3
Dan

@Matthias Hopf回答

V1.3.5の回答を更新しました。古いイベントと*一緒にイベント。

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

私が見つけたすべてのメソッド(socket.io-wildcardおよびsocketio-wildcardを含む)は、私にとってはうまくいきませんでした。 socket.io 1.3.5には$ emitがないようです...

Socket.ioコードを読んだ後、DID work:

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

これは他の人にとっても解決策かもしれません。しかし、ATMは、既存の「ソリューション」に問題があるように見える人が誰もいない理由を正確には理解していません。何か案は?多分それは私の古いノードバージョン(0.10.31)です...

1
Matthias Hopf

Angular 6およびnpmパッケージを使用しています:ngx-socket-io

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

...

constructor(private socket: Socket) { }

...

ソケットを接続した後、このコードを使用します。これはすべてのカスタムイベントを処理しています...

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