
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は一つだけなので、今の所はこれで問題ない。





