Динамические пространства имен Socket.IO
Как использовать динамические пространства имен в socket.io.
Я просматриваю (бедный) документацию, и он говорит, что пространства имен должны использоваться следующим образом:
io.of('/news')
io.of('/akfda')
Чтобы использовать пространство имен, вы делаете io.of("/namespace")
.
Нужно ли регистрировать каждое пространство имен на сервере? Возможно, я хочу пространство имен для динамического контента.
Как я могу сделать что-то вроде:
io.of('/:somethign/:id')
Ответы
Ответ 1
Socket.IO поддерживает "комнаты" (https://github.com/LearnBoost/socket.io/wiki/Rooms), вы можете использовать его вместо пространств имен. Также, когда вам нужна динамическая маршрутизация (и вы используете экспресс в своем приложении) - лучший способ - использовать использование маршрута-движка из ящика.
Однако, если вы все еще считаете, что вам нужно динамическое пространство имен в socket.io, вот небольшой пример того, как он может быть реализован:
На стороне пользователя:
var connect = function (ns) {
return io.connect(ns, {
query: 'ns='+ns,
resource: "socket.io"
});
}
var socket = connect('/user/12');
Серверный:
var url = require('url');
, ev = new events.EventEmitter()
// <ns name>: <ns regexp>
var routes = {
// /user/:id
'user': '^\\/user\\/(\\d+)$',
// /:something/:id
'default': '^\\/(\\\w+)\\/(\\d+)$'
};
// global entry point for new connections
io.sockets.on('connection', function (socket) {
// extract namespace from connected url query param 'ns'
var ns = url.parse(socket.handshake.url, true).query.ns;
console.log('connected ns: '+ns)
//
for (var k in routes) {
var routeName = k;
var routeRegexp = new RegExp(routes[k]);
// if connected ns matched with route regexp
if (ns.match(routeRegexp)) {
console.log('matched: '+routeName)
// create new namespace (or use previously created)
io.of(ns).on('connection', function (socket) {
// fire event when socket connecting
ev.emit('socket.connection route.'+routeName, socket);
// @todo: add more if needed
// on('message') -> ev.emit(...)
});
break;
}
}
// when nothing matched
// ...
});
// event when socket connected in 'user' namespace
ev.on('socket.connection route.user', function () {
console.log('route[user] connecting..');
});
// event when socket connected in 'default' namespace
ev.on('socket.connection route.default', function () {
console.log('route[default] connecting..');
});
Я надеюсь, что это поможет вам!
Ответ 2
Я бы использовал "комнаты" для поддержки вашего динамического контента.
Сторона сервера
var server = require('http').createServer(),
io = require('socket.io')(server);
io.on('connection', function(socket){
var room = socket.handshake['query']['r_var'];
socket.join(room);
console.log('user joined room #'+room);
socket.on('disconnect', function() {
socket.leave(room)
console.log('user disconnected');
});
socket.on('chat message', function(msg){
io.to(room).emit('chat message', msg);
});
});
server.listen(3000);
Клиентская сторона
var socket_connect = function (room) {
return io('localhost:3000', {
query: 'r_var='+room
});
}
var random_room = Math.floor((Math.random() * 2) + 1);
var socket = socket_connect(random_room);
socket.emit('chat message', 'hello room #'+random_room);
....
Ответ 3
Вот один из способов. Вот подкомплекс socket.io, который я создал для решения проблемы:
https://github.com/PencilCode/dynamic.io
Этот подкласс добавляет динамические пространства имен, а также поддержку виртуального хоста (каждый хост может пойти в свое собственное дерево пространства имен, если хотите). В этом репо есть несколько примеров.
Вот универсальный прослушиватель socket.io, который прослушивает каждое запрошенное пространство имен и регистрирует сообщение для каждого сокета, который подключается. Вы можете прослушивать другое регулярное выражение для прослушивания любого подмножества пространств имен.
Он работает со стандартной клиентской библиотекой socket.io без каких-либо изменений.
var DynamicServer = require('dynamic.io');
io = DynamicServer({
host: true, // Enable virtual host handling
publicStatus: true // Enable /socket.io/status page.
});
// Any number of namespace patterns can be set up.
// This is an example of a single catch-all pattern.
io.setupNamespace(/.*/, function(nsp) {
nsp.on('connect', function(socket) {
console.log('a socket connected on', nsp.fullname());
});
nsp.expire(function() {
console.log(nsp.fullname(), 'is expiring');
});
});
io.listen(8888);
Ответ 4
Сервер
var MAX_CLIENTS = 5;
var namespace_queue = [];
function searchObjectOnArray(nameKey, myArray) {
for (var i = 0; i < myArray.length; i++) {
if (myArray[i].id === nameKey) {
return myArray[i];
}
}
}
function createNamespace(data){
var ns = {
//id: require('node-uuid')(),
id : data.name,
clients: 0,
};
namespace_queue.push(ns);
return ns;
}
createNamespace({name: 'primer'});
io.of('').on('connection', function(socket){
console.log('-' + socket.id);
/// Welcome to the new client
socket.emit('Welcome', {SocketId : socket.id});
socket.on('JoinToApp', function (data, callback) {
var namespaceToConnect = searchObjectOnArray(data.namespace, namespace_queue)
if(namespaceToConnect.clients <= MAX_CLIENTS){
var dynamicNamespace = io.of('/' + namespaceToConnect.id);
dynamicNamespace.on('connection', function(ns_socket){
console.log('user connected to ' + namespaceToConnect.id);
dynamicNamespace.emit('hi', 'everyone!');
});
namespaceToConnect.clients++;
}
callback({namespaces:namespace_queue});
})
socket.on('createNamespace',function(data,join_cb){
createNamespace(data);
join_cb({message:'Namespace created'});
});
});
Client
<input id="namespaceInput" type="text" placeholder="New namespace name">
<input id="namespaceToConnect" type="text" placeholder="namespace to connect">
<button onclick="javascript: createNamespace()">Create Namespace</button>
<button onclick="javascript: joinToNamespace()">Connect to Namespace</button>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script>
var socket = null;
(function(){
socket = io.connect('http://localhost:3000/');
})()
function createNamespace(){
var namespaceName = document.getElementById("namespaceInput").value;
socket.emit('createNamespace', {name : namespaceName}, function(data){
alert(data.message);
})
}
function joinToNamespace(){
var name = document.getElementById("namespaceToConnect").value;
socket.emit('JoinToApp', {namespace: name}, function(data){
console.log('Namespaces created:');
console.log(data)
var ns_socket = io.connect('http://localhost:3000/' + name);
ns_socket.on('connect',function(){
console.log('joined namespace ' + name);
});
ns_socket.on('hi', function(data){
console.log('hi ' + data)
})
});
}
</script>
Подробнее о: https://ingcamilorodriguez.wordpress.com/2016/06/21/como-hacer-namespaces-dinamicos-en-socket-io/
Ответ 5
Начиная с версии 2.1.1
я смог заставить ее работать с этим:
wss.of((nsp, query, next) => {
const { token } = query;
// Do your authentication or whatever here...
// If success
next(null, nsp);
}).on('connect', (socket) => {
// socket connected to your namespace
});