Socket.ioから部屋の一覧を取得(ついでにユーザーの一覧も)

前回は adapter.sids からユーザーの一覧を取得したが、今回は adapter.rooms から部屋の一覧を取得してみようと思う。

例えばユーザーがチャットロビーにアクセスした際、

  • 自分以外のユーザーのリスト。
  • 立てられている部屋のリスト。
  • 部屋ごとに参加しているユーザーのリスト。

これらの情報を画面に描画したいハズだ。

 

adapter.rooms を良い感じに型変換して送信

adapter.sids で一覧を送信しようとした時に、Map 型や Set 型をそのまま送ると上手く行かない事を学んだので、今回は予めそれらを考慮して書いてみる。

 

server.js のソース

io.of("/").on("connection", socket => {
	const rooms = io.of("/").adapter.rooms;
	const param = {id: socket.id, rooms: [], users: []};
	
	rooms.forEach((room, key) => {
		if(!room.has(key)) {
			param.rooms.push({name: key, join: [...room]});
		} else if(socket.id !== key) {
			param.users.push(key);
		}
	});
	
	io.to(socket.id).emit("test1", param);
});

こんな感じでどうかな。

# dev tool console
{
	id: "<socket.id-A>"
	rooms: []
	users: []
}

想定通りのデータがブラウザで受け取れたので、それぞれ解説していく。

 

クライアントに渡すパラメータ(Line: 3)

const param = {
	id: socket.id,	// 自分のソケット ID
	rooms: [],			// 任意生成した部屋のリスト
	users: []				// 自分以外のソケット ID のリスト
};

id

クライアントがローカルで自分のソケット ID を認識するため。

rooms

ソケット生成時に自動で作成&入室される部屋を除いた部屋、つまり任意生成された部屋(=ユーザーが立てた部屋)のリスト、中身は部屋名と参加しているソケット ID のリストが格納される。

users

自分のソケット ID を除いた、全ユーザーのリスト。

 

部屋判定(Line: 6)

Socket.ioのRoomsを学習するで検証した時、接続数2で任意の部屋に入るとこうなっていた。

Map(3) {
'<socket.id-A>’ => Set(1) { '<socket.id-A>’ },
'room1’ => Set(2) { '<socket.id-A>’, '<socket.id-B>’ },
'<socket.id-B>’ => Set(1) { '<socket.id-B>’ }
}

つまり部屋名(key)と同じ名前の参加者(id)が居なければ、それは「任意に立てた部屋」だと言う事になるため、room.has(key) == false としてやれば良い。(この場合は room1 だけ該当する)

 

ユーザー判定(Line: 8)

上記の条件を満たさない、つまり部屋名と参加者名が同じ場合はユーザーと言う事になる。

しかしユーザーリストでは自分の情報は必要ないので、socket.id !== key としてやれば自分以外のユーザーが取得できると言う仕組み。

 

任意の部屋を立てて複数人数入室させてみる

server.js のソース4行目に socket.join(“room1"); とだけ追記したコードを実行し、別タブを4枚開いて接続数4にした時に取得出来た情報がこちらになる。

# dev tool console
{
	id: "<socket.id-D>"
	rooms: [
		0:
			join: [
				0: "<socket.id-A>"
				1: "<socket.id-B>"
				2: "<socket.id-C>"
				3: "<socket.id-D>"
			]
			name: "room1"
	]
	users: [
		0: "<socket.id-A>"
		1: "<socket.id-B>"
		2: "<socket.id-C>"
	]
}

想定通りだが、自分が join しているルームはフラグを持たせるなどしてアクセスしやすくした方が良いかも知れないね。

 

たまになんかエラーが出る

Chrome で複数タブを開いて検証していると、

Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received

と言うエラーがコンソールに表示される事がある。

詳しい条件は分からないが、タブを開いた後しばらく放置すると再現している気がする。

これは要調査かなー。

 

関連記事

Socket.ioからユーザーの一覧を取得(ソケットIDのリスト)

JavaScriptNode.js,Socket.io

Posted by theuri