Как выполнить эмиссию из пространства имен по умолчанию в пользовательское пространство имен? - PullRequest
0 голосов
/ 30 января 2019

У меня есть приложение React, использующее Socket.io.Я использую пространство имен по умолчанию / и пользовательское пространство имен /test.Мне нужно иметь возможность передавать из пространства имен в другое, но мне удалось только заставить его работать от обычая до значения по умолчанию.

На стороне клиента прослушиватель событий находится в корне (App.js):

componentDidMount() {
  socket.on('test_listener', (data) => {
    // Some code
  })
}

Соединение инициализируется с помощью приращения:

import socketIOClient from 'socket.io-client';

const initialState = {
  initializeSocket: socketIOClient('http://localhost:3000/'),
  ...
}

На стороне сервера приведен код:

io.on('connection', function (socket) { 

  socket.on('something', (data) => {

    io.of('/test').emit('test_listener', data); // Not working
    socket.broadcast.emit('test_listener', data); // Is working

  })

});

Я точно знаю, что *Предполагается, что 1015 * будет работать так, как это указано в файле Emit Socket.io Emit .И прослушиватель событий на стороне клиента работает, так как я получаю что-то с broadcast.emit.

Плюс, я могу излучать от /test до / с этим кодом:

socket.on('join_namespace_test', data => {

  // [...] Some code to check if the namespace exists

  io.of('/test').on('connection', function (nspSocket) {

    nspSocket.on('do_something', (data) => {
      io.of('/').emit('another_action', data); // This one is working fine
    })

  })

  // [...] Some code to add the user to the namespace /test (switching from default)
}

Есть идеи, почему не работает emit от / до /test? Я не получаю никакой ошибки, ничего не происходит.


Редактировать: после дальнейших исследований я обнаружил этот пост :

Вы не можете "переключать" пространства имен в существующем соединении.Вы подключаетесь к определенному пространству имен, когда соединение установлено и однажды установлено, его нельзя изменить.

Чтобы быть уверенным, что проблема не связана с другой частью проекта, я воспроизвел еевопрос на скрипке.Излучение от обычного к обычному все еще не работает, и я также заметил, что broadcast ведет себя странно, когда клиент переключается с обычного на пользовательский и затем возвращается к стандартному (он отправляет отправителю, а это не должно).

Итак, учитывая тот факт, что проблема может заключаться в том, что клиент переключается между стандартным и настраиваемым пространством имен, а не самим emit, возможно, комнаты будут лучшим вариантом?Или, может быть, я должен найти способ сбросить соединения перед переключением, но рекомендуется ли это?

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

После многих тестов единственное сработавшее решение - закрыть предыдущее соединение перед переключением на другое пространство имен, а затем снова вызвать прослушиватель сокетов.Когда socket.on инициализируется, он будет работать только в том случае, если пространство имен / соединение установлено. Этот пост помог мне найти решение .

Для простого кода без избыточности решение может выглядеть следующим образом (на стороне клиента, никаких изменений на стороне сервера не требуется):

var socket = io();
listen();

function switchNamespace(namespace) {
  socket.close(); // Close the current connection
  socket = io(namespace);
  listen();
}

function listen() {
  socket.on('test_listener', (data) => {
    // Some code
  })
}

В качестве примечания, инициализация io.of('/namespace').on('connection', ... внутри или вне значения по умолчанию io.on('connection', ... не имела никакого значения.

В нашем случае это решение не соответствовало текущей структуре проектапоэтому мы решили использовать комнаты.

0 голосов
/ 01 февраля 2019

Можете ли вы показать мне, как инициализируется соединение на стороне клиента?

Должно быть так:

const socket = io('/test')

Если вы транслируете что-то в пространство имен default и клиентполучить его, это означает, что клиент подключен к пространству имен /, а не к /test.

На стороне клиента я уверен, что вы не можете прослушивать несколько пространств имен в одном сокете.Если вы хотите сделать это, вам нужно инициализировать несколько сокетов на клиенте:

const socketDefault = io()
const socketTest = io('/test')

РЕДАКТИРОВАТЬ

Ваш другой ответ хорош, если вынужно использовать только одно пространство имен одновременно.

Однако, если вы хотите истинную обработку нескольких пространств имен, код немного лучше может быть следующим:

class Sockets {

  // Used as Handler for the proxy for `multi` method, should work, but didn't test it
  get (target, prop) {
    return (...args) => {
      const output = [];
      for(const alias of target._aliases) {
        output.push(target._sockets[alias][prop](...args))
      }
      return output;
    }
  }

  // Used to proxy methods, and only methods
  multi(aliases) {
    return new Proxy({ _sockets: this, _aliases: aliases }, this); // Use the above `get` for all undefined methods
  }

  addNamespace(alias, namespace) {
    if (this[alias]) {
      return false
    }

    Object.defineProperty(this, alias, {
      enumerable: true,
      writable: false,
      configurable: false,
      value: io(namespace)
    })
  }
}

const sockets = new Sockets()
sockets.addNamespace('default')
sockets.addNamespace('test', '/test')
sockets.addNamespace('toto', '/toto')

sockets.test.on('test_listener', (data) => {
  // Some code
})

sockets.toto.on('test_listener', (data) => {
  // Some code
})

sockets.multi(['test', 'toto', 'default']).on('common_listener', (data) => {

})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...