LoginSignup
86
75

More than 5 years have passed since last update.

Socket.ioを使ったチャットルーム ロジックの実装

Last updated at Posted at 2015-07-10

Node.jsの勉強がてら地図上でお話しできるチャットアプリを作成していたら、チャットルームの管理が面倒なので、FacebookのMessengerで管理しているグループと連動できないかと思ってやってみた雑記です。
FacebookメッセンジャーのConversation IDを利用してチャットルームUIを作るの続編。

チャットルーム ロジック実装

socket.ioのRoomsを使ったチャットルームの作り方

チャットルームはSocket.ioのRoomsを使って実現します。RoomsはSocketのチャンネルであり、一度Roomsでチャンネルを初期化してしまえば、Socket.ioでチャンネルごとに送信先を分けることができます。

  • socket.io: Rooms

io.js(Room実装前)

io.js
    var socketio = require('socket.io');

    function io(server) {
      var io = socketio.listen(server);

      io.on('connection', function (socket) {
        socket.on('chat message', function(msg) {
          io.emit('chat message', msg);
        });
        socket.on('map message', function(msg) {
          io.emit('map message', msg);
        });
      });
    }
    module.exports = io;

上記コード内に以下のコードを追加してRoomを初期化。

socket.join('<Room ID>');

メッセージ配信時に特定のRoomにのみ配信を行うためにRoom ID指定したioでemitする。

io.to('<Room ID>').emit('chat message', msg);

これだけ。
以下、Room実装後のio.js。function io内抜粋。

io.js(Room実装後)

io.js
    var io = socketio.listen(server);

    var store = {};

    io.on('connection', function (socket) {
      socket.on('join', function(msg) {
        usrobj = {
          'room': msg.roomid,
          'name': msg.name
        };
        store[msg.id] = usrobj;
        socket.join(msg.roomid);
      });

      socket.on('chat message', function(msg) {
        io.to(store[msg.id].room).emit('chat message', msg);
      });
      socket.on('map message', function(msg) {
        io.to(store[msg.id].room).emit('map message', msg);
      });
    });

この後はおまけです。

チャットルームを永続的に残さない、かつユーザー1人に対して参加できるチャットルームを1ルームのみとして、FacebookのMessengerで管理されているグループと同期してチャットルームを生成する仕組みです。

チャットルームUI実装で取得したFacebookのConversation IDをRoom IDに使用して実装

ルームに入る際にルーム初期化のための送信メッセージ('join')をemitする。
roomidにConversation IDが入ります。
Conversation IDの取得はFacebookメッセンジャーのConversation IDを利用してチャットルームUIを作るを参考にしてください。

view/index.ejs
          socket.emit('join', {
            roomid: e.target.id,
            name: myname,
            id: myid
          });

socket.on('join')で渡されたmsg.idにはFacebookのConversation IDが入ってるので、これをRoom IDとしてsocket.joinする。

io.js
    socket.join(msg.roomid);

これにより、RoomはFacebookのメッセンジャーグループと同期される。

連想配列(store = {})を作って、そこに接続ユーザーの情報を格納して、emitする際にstoreからRoom IDを取得して利用する。

io.js
    io.to(store[msg.id].room).emit('chat message', msg);

退出の実装

最後に、Socket切断時の自動退出の実装です。

socket.idとFacebookユーザーIDを紐付けて管理します。

io.js
    var idstore = {};

    // JOIN時に格納
    idstore[socket.id] = { 'id': msg.id };

Webアプリなのでセッションが切れると接続も切れる。
(※今回は明示的に切断するためのUIは作ってない)

Socketのdisconnect時にidstore[socket.id].idで退出したユーザーを確定する。退出メッセージ送信後は不要なidstoreを削除。

io.js
      socket.on('disconnect', function() {
        if (idstore[socket.id]) {
          var _roomid = store[idstore[socket.id].id].room;
          socket.leave(_roomid);
          io.to(_roomid).emit('chat message', {
            id: idstore[socket.id].id,
            name: store[idstore[socket.id].id].name,
            text: '退出!'
          });
          delete idstore[socket.id];
        }
      });

メモ:if (idstore[socket.id])内で実行するようにしておかないとサーバー側のエラーが出てHerokuで動作させているアプリがエラーで使えなくなった。ログを見てると切断後ポーリングをして接続状況を確認してるのか、再度disconnectが発行されて処理に失敗してる感じ。

以上です。

86
75
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
86
75