Использовать socket.io в контроллерах

17

Мне нужен только socket.io для отправки сообщений клиентам, если новый объект вставляется в базу данных. Поэтому моя идея состояла в том, чтобы выпустить сообщение непосредственно из метода вставки моего контроллера. В моем файле server.js iam создает объект socket.io и пытаюсь сделать его доступным для других модулей:

var server = require('http').createServer(app);
var io = require('socket.io').listen(server);

//make socket io accessible for other modules
module.exports.io = io;

В моем контроллере я пытаюсь использовать socket.io следующим образом:

var io = require('../server').io;
...
io.sockets.on("connection", function(socket){
  passportSocketIo.filterSocketsByUser(io, function (user) {
    return user.workingAt === socket.handshake.user.workingAt;
  }).forEach(function(s){
    s.send("news", insertedObject);
  });
});

И здесь ям застрял. Событие «соединение» никогда не будет запущено, поэтому сообщение не будет выбрано. Это правильный способ использования socket.io в отдельных файлах? К сожалению, я не могу найти сложный пример socket.io.

    
задан tschiela 24.10.2013 в 09:03
источник
  • вы не можете просто позвонить io.sockets.emit ()? –  Max Girkens 24.10.2013 в 09:11
  • Я хочу отправить сообщение не всем пользователям. Поэтому мне нужен объект сокета для фильтрации активных сокетов ... я обновил свой код –  tschiela 24.10.2013 в 09:15
  • У меня возникнет соблазн либо отладить приложение, либо пройти через то, что происходит, когда сокеты создаются и фильтруются, или добавлять некоторые записи для достижения того же эффекта. Одно из ваших предположений о том, как все работает, будет своенравным. Я предполагаю, что вы хотите отправлять сообщения в определенные сокеты при возникновении HTTP-запроса? Я думаю, что ваш подход должен работать, но лично я бы вытащил весь доступ к socket.io в одном модуле-оболочке и экспортировал то, что мне нужно, например. mysockets.start (порт) и mysockets.sendNews (пользователь, msg) –  Richard Marr 24.10.2013 в 09:47
  • В настоящий момент iam завершает весь файл socket.io в отдельном модуле. Я отчитываюсь –  tschiela 24.10.2013 в 09:54

1 ответ

43

Вы пытаетесь инвертировать поток управления. Способ сделать это для вашего контроллера, чтобы реализовать интерфейс (API), который ваш сервер может использовать для передачи управления.

Простым примером может быть:

В mycontroller.js

// no require needed here, at least, I don't think so

// Controller agrees to implement the function called "respond"
module.exports.respond = function(socket_io){
    // this function expects a socket_io connection as argument

    // now we can do whatever we want:
    socket_io.on('news',function(newsreel){

        // as is proper, protocol logic like
        // this belongs in a controller:

        socket.broadcast.emit(newsreel);
    });
}

Теперь в server.js :

var io = require('socket.io').listen(80);
var controller = require('./mycontroller');

io.sockets.on('connection', controller.respond );

Этот пример прост, потому что API-интерфейс контроллера выглядит точно так же, как обратный вызов socket.io. Но что, если вы хотите передать другие параметры контроллеру? Как и сам объект io или переменные, представляющие конечные точки? Для этого вам понадобится немного больше работы, но это немного. Это в основном тот же трюк, который мы часто используем для создания или закрытия замыканий: генераторы функций:

В mycontroller.js

module.exports.respond = function(endpoint,socket){
    // this function now expects an endpoint as argument

    socket.on('news',function(newsreel){

        // as is proper, protocol logic like
        // this belongs in a controller:

        endpoint.emit(newsreel); // broadcast news to everyone subscribing
                                     // to our endpoint/namespace
    });
}

Теперь на сервере нам потребуется немного больше работы, чтобы передать конечную точку:

var io = require('socket.io').listen(80);
var controller = require('./mycontroller');

var chat = io
  .of('/chat')
  .on('connection', function (socket) {
      controller.respond(chat,socket);
  });

Обратите внимание, что мы пропускаем socket прямо, но мы фиксируем chat через закрытие. При этом вы можете иметь несколько конечных точек с собственными контроллерами:

var io = require('socket.io').listen(80);
var news_controller = require('./controllers/news');
var chat_controller = require('./controllers/chat');

var news = io
  .of('/news')
  .on('connection', function (socket) {
      news_controller.respond(news,socket);
  });

var chat = io
  .of('/chat')
  .on('connection', function (socket) {
      chat_controller.respond(chat,socket);
  });

Собственно, вы можете использовать несколько контроллеров для каждой конечной точки. Помните, что контроллеры ничего не делают, кроме подписки на события. Это сервер, который выполняет прослушивание:

var io = require('socket.io').listen(80);
var news_controller = require('./controllers/news');
var chat_controller = require('./controllers/chat');

var chat = io
  .of('/chat')
  .on('connection', function (socket) {
      news_controller.respond(chat,socket);
      chat_controller.respond(chat,socket);
  });

Он даже работает с простым socket.io (без конечных точек / пространств имен):

var io = require('socket.io').listen(80);
var news_controller = require('./controllers/news');
var chat_controller = require('./controllers/chat');

io.sockets.on('connection', function (socket) {
    news_controller.respond(socket);
    chat_controller.respond(socket);
});
    
ответ дан slebetman 24.10.2013 в 10:04
источник
  • Спасибо за прекрасный ответ, который выглядит очень непрозрачно. Но у меня есть один вопрос: что делать, если я хочу использовать socket.io в нескольких контроллерах? –  tschiela 24.10.2013 в 10:14
  • Это описано во второй части - используйте отдельные конечные точки для каждого контроллера. –  slebetman 24.10.2013 в 10:24
  • Спасибо, приветствую ответ –  tschiela 24.10.2013 в 10:28
  • Добавил больше примеров к моему ответу. –  slebetman 24.10.2013 в 10:32
  • Вам понадобится другой контроллер для обработки socket.io, поскольку это другой сервис. Но для emit только обязательно, вы можете просто передать socket.io таким же образом. Попросите вашего контроллера принять req, res, io в качестве аргументов, а затем в app.post второй аргумент будет функцией (req, res) {TestCtrl.insert (req, res, io)} –  slebetman 24.10.2013 в 16:13
Показать остальные комментарии