Socket.IOのチャットアプリで誰が入力中なのかを出力したい
前回までで簡易的なチャットアプリを作成することができた。
この時点ではチャットのページを知っている人は誰でも参加することができてしまうため、
AさんとBさんのみといったユーザを限定したチャットではない。
直近の目標はLineやChatWorkのようにユーザを限定したメッセージのやりとりなので、
ユーザを限定する方法というものを模索してみる。
Socket.IOにはNamespacesとRoomsいう概念がある。
簡単にまとめると、
Namespacesは機能毎にチャットを作る。chatとかnewsとか
Roomsはチャット内でカテゴリ分けする。
Socket.IO — Rooms and Namespaces
詳細は特に触れずに簡単な接続実験を行ってみたいと思う。
※実験自体は次回に記載する
前回まで作成してきた各ファイルを下記のように書き換える。
server.js
var fs = require("fs"); var http = require("http"); var server = http.createServer(); server.on("request", function(request, response){ var stream = fs.createReadStream("index.html"); response.writeHead(200, {"Content-Type":"text/html"}); stream.pipe(response); }); server.listen(8080); var io = require("socket.io").listen(server); // ユーザ管理ハッシュ var userHash = {}; // Namespacesを利用する var chatNS = io.of('/chat'); chatNS.on("connection", function(socket){ // Room(Namespacesで分けた時、roomも利用した方が良いみたい) var roomName = "default"; // WebSocketで接続の際にどのroomに参加するか? socket.join(roomName); // 接続開始のカスタムイベント(接続元ユーザを保存し、他ユーザへ通知) socket.on("connected", function(name){ var msg = name "が入室しました"; userHash[socket.id] = name; chatNS.to(roomName).emit("pushlish", {value: msg}); }); // メッセージ送信カスタムイベント socket.on("publish", function(data){ chatNS.to(roomName).emit("publish", {value:data.value}); }); let nowTyping = 0; socket.on("start typing", function(){ if (nowTyping <= 0) { socket.to(roomName).emit("start typing", userHash[socket.id]); } nowTyping++; setTimeout(function(){ nowTyping--; if (nowTyping <= 0) { socket.to(roomName).emit("stop typing"); } }, 3000); }); socket.on("stop typing", function(){ nowTyping = 0; socket.broadcast.emit("stop typing"); }); // 接続終了組み込みイベント(接続元ユーザを削除し、他ユーザへ通知) socket.on("disconnect", function(){ if(userHash[socket.id]){ var msg = userHash[socket.id] + "が退出しました"; delete userHash[socket.id]; chatNS.to(roomName).emit("publish", {value: msg}); } }); });
Namespacesを利用する時にvar chatNS = io.of("/chat");とすることで、機能別に分けることができ、
connectionイベントの実行の際に今までio.on("connection", 処理);としていた箇所を、
chatNS.on("connection", 処理);とすることで個別に決めたnamespaceで動作するようになる。
この時、他にもあったio.on(イベント, 処理);をchatNS.on(イベント, 処理);とすることで、
各namespace内で動作するイベントとして登録することができる。
各ブラウザがサーバに接続した直後に、socket.join(room名)でroomに参加させ、
chatNS.to(room名).emit(イベント名);で更にroomという単位で処理を指示することができる。
※カテゴリ分けが1つであっても、namespacesを利用している際にroomを指定しないと意図しない動作がいろいろと見られたので、room一つでも処理は入れておいが方が良さそう。
続いて、フロント側で、index.htmlの修正箇所は
var socket = io.connect("http://localhost:8080");
を
var socket = io.connect("http://localhost:8080/chat");
とするだけで良い。
この状態で実行してみると、
今まで通り問題なく動作している。
namespaceは一つだけなので、今の所はこれで問題ない。