Клієнт Socket.io: відповідати на всі події одним обробником?


83

Чи можливо, щоб клієнт 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 на стороні клієнта.

Чи можливо це? Як?


Я відкрив наступну проблему щодо переадресації всіх типів подій, а також додав знайдені рішення: github.com/Automattic/socket.io/issues/1715
Пітер Уітховен

Відповіді:


25

Схоже, бібліотека 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;
  };


У 2019 році я не думаю, що це вже так.
Urasquirrel

82

Оновлене рішення для 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);
});

Жодна з відповідей не спрацювала для мене, хоча відповідь Матіаса Хопфа та Мароса Пікселя наблизилася, це моя скоригована версія.

ПРИМІТКА: це лише вловлює власні події, а не підключається / відключається тощо


2
Дякую, це допомогло мені налагодити відсутні події!
Майтрея

1
На жаль, не працює з такими речами, як 'user. *' ;. Можливо, мені вдасться це реалізувати.
C4d

Привіт, дуже добре, але це може бути корисно, якщо у вас є кілька прикладів виводу ^^ Я відчуваю, що мені потрібно запустити код, щоб зрозуміти вашу відповідь :)
grobouDu06

24

Нарешті , є модуль під назвою 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);

11

Ось ідіть ...

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

Це дозволить відловлювати події , як connecting, connect, disconnect, reconnectingтеж, так що НЕ все одно беруть.


Збірка Socket.IO.js: 0.9.10, розробка.
Kaustubh Karkare

3
Це в підсумку вийшло?
hacklikecrack

9

Примітка: ця відповідь справедлива лише для socket.io 0.x

Ви можете замінити сокет. $ Emit

За допомогою наступного коду у вас є дві нові функції:

  • Зафіксуйте всі події в пастці
  • Захоплювати лише події, які не перехоплені старим методом (це прослуховувач за замовчуванням)
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));
});

Будь-які поради щодо операції синхронізації перед викликом застосовуються. setTimeout (function () {original_ $ emit.apply (socket, ['*']. concat (args)); if (! original_ $ emit.apply (socket, аргументи)) {original_ $ emit.apply (socket, [ 'за замовчуванням']. concat (args));}}, 2000);
Енкі

Я використовую Socket.io 1.3.6 і не схоже, щоб бути $ методом випромінюють в socketбільше
raimohanska

Справді. Перевірте відповідь @Flion на версії 1.x
leszek.hanusz

7

У поточному документі GitHub (квітень 2013 р.) Щодо викритих подій згадується a socket.on('anything'). Здається, що-небудь - це заповнювач для назви спеціальної події, а не фактичне ключове слово, яке охоплює будь-яку подію.

Я щойно почав працювати з веб-сокетами та Node.JS, і мені одразу виникла необхідність обробити будь-яку подію, а також виявити, які події були надіслані. Не можу повністю повірити, що ця функціональність відсутня в socket.io.


5

socket.io-клієнт 1.7.3

Станом на травень 2017 року жодне з інших рішень не змогло працювати так, як я хотів - зробив перехоплювач, використовуючи 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)
  }
})

Список літератури:


3

На цій темі триває тривала дискусія на сторінці випуску сховища Socket.IO. Там розміщено різноманітні рішення (наприклад, заміщення EventEmitter на EventEmitter2). lmjabreu випустив ще одне рішення кілька тижнів тому: модуль npm під назвою socket.io-wildcard, який виправляє підстановку у Socket.IO (працює з поточним Socket.IO, ~ 0.9.14).


4
Але це лише на стороні сервера ... його модуль не можна використовувати на стороні клієнта (браузер)
Сандер

3

Оскільки ваше запитання було досить загальним у питанні рішення, я запропоную це питання, яке не вимагає злому коду, а лише зміну способу використання сокета.

Я просто вирішив, що мій клієнтський додаток надсилає точно таку ж подію, але з іншим корисним навантаженням.

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

А на сервері щось на кшталт ...

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

Я не знаю, чи завжди використання однієї і тієї ж події може спричинити якісь проблеми, можливо, зіткнення якихось масштабів, але це моїм цілям дуже добре служило.


2

Незважаючи на те, що це старе питання, я маю ту ж проблему, яку вирішив за допомогою власного сокета Node.js, який має подію .on ('data'), що спрацьовує кожного разу, коли надходять деякі дані. Отже, це те, що я зробив до цього часу:

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

Усі знайдені мною методи (включаючи socket.io-wildcard та socketio-wildcard) для мене не працювали. Очевидно, у socket.io 1.3.5 немає $ emit ...

Після прочитання коду socket.io я виправив таке, що працювало:

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

Це може бути рішенням і для інших. Однак банкомат, я точно не розумію, чому, здається, ніхто більше не має проблем із існуючими "рішеннями"?!? Будь-які ідеї? Можливо, це моя стара версія вузла (0.10.31) ...


Я можу підтвердити, що це працює, і, як ви зауважили, єдиний, який працює (у тому сенсі: і для мене теж). Дуже дякую!
позначка

1

Відповідь @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
};

0

Я використовую 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}]`);
  }
});

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.