I've found a lot of good background on this issue already on stackoverflow and in the socketio docs but I'm not able to apply what I've learned to fix my code base.
I encounter the issue when I try to get a list of all the clients in a namespace and specific room. In socketio version 2 (the old way) you are able to get a list of all the sockets in the /chat namespace and 'general' room using the code:
io.of("/chat").in('general').clients((error, clients) => {
console.log(clients); // => [Anw2LatarvGVVXEIAAAD]
});
However, as of version 3 the .clients() method is no longer used and has been renamed .allSockets() which returns a promise-based Set data type:
await ioServer.of('/chat').in('general').allSockets();
I'm trying to use the .allSockets() syntax to grab the value within the returned promise for my /wiki namespace and current room which I've assigned to the variable roomToJoin but I'm missing something fundamental about how the async-await syntax should be used. I keep getting the error:
(node:46560) UnhandledPromiseRejectionWarning: TypeError: ioServer.of(...).in(...).allSockets is not a function
My code and files are below. Any help would be greatly appreciated.
slack.js
const express = require("express");
const app = express();
const Server = require("socket.io");
let namespaces = require("./data/namespaces");
app.use(express.static(__dirname + "/public"));
const expressServer = app.listen(9000);
const ioServer = new Server(expressServer);
ioServer.on("connection", (socket) => {
let nsData = namespaces.map((ns) => {
return {
img: ns.img,
endpoint: ns.endpoint,
};
});
socket.emit("nsList", nsData);
});
namespaces.forEach((namespace) => {
ioServer.of(namespace.endpoint).on("connection", (nsSocket) => {
nsSocket.emit("nsRoomLoad", namespaces[0].rooms);
nsSocket.on("joinRoom", async (roomToJoin, numberOfUsersCallback) => {
nsSocket.join(roomToJoin);
const clients = await ioServer.of('/wiki').in(roomToJoin).allSockets();
console.log(Array.from(clients));
numberOfUsersCallback();
});
});
});
clientScripts.js
const socket = io("http://localhost:9000");
let nsSocket = "";
socket.on("nsList", (nsData) => {
let namespacesDiv = document.querySelector(".namespaces");
namespacesDiv.innerHTML = "";
nsData.forEach((ns) => {
namespacesDiv.innerHTML += `<div class="namespace" data-ns=${ns.endpoint} ><img src="${ns.img}" /></div>`;
});
Array.from(document.getElementsByClassName("namespace")).forEach((elem) => {
elem.addEventListener("click", (e) => {
const nsEndpoint = elem.getAttribute("data-ns");
console.log(`${nsEndpoint} I should go to now`);
});
});
joinNs('/wiki');
});
joinNs.js
function joinNs(endpoint) {
nsSocket = io(`http://localhost:9000${endpoint}`);
nsSocket.on("nsRoomLoad", (nsRooms) => {
let roomList = document.querySelector(".room-list");
roomList.innerHTML = "";
nsRooms.forEach((room) => {
let glyph;
if (room.privateRoom) {
glyph = "lock";
} else {
glyph = "globe";
}
roomList.innerHTML += `<li class='room'><span class="glyphicon glyphicon-${glyph}"></span>${room.roomTitle}</li>`;
});
let roomNodes = document.getElementsByClassName("room");
Array.from(roomNodes).forEach((elem) => {
elem.addEventListener("click", (e) => {
console.log("Someoneclickon ", e.target.innerText);
});
});
const topRoom = document.querySelector(".room");
const topRoomName = topRoom.innerText;
joinRoom(topRoomName);
});
nsSocket.on("messageToClients", (msg) => {
console.log(msg);
document.querySelector("#messages").innerHTML += `<li>${msg.text}</li>`;
});
document
.querySelector(".message-form")
.addEventListener("submit", (event) => {
event.preventDefault();
const newMessage = document.querySelector("#user-message").value;
socket.emit("newMessageToServer", { text: newMessage });
});
}
joinRoom.js
function joinRoom(roomName) {
nsSocket.emit("joinRoom", roomName, (newNumberOfMembers) => {
document.querySelector(
".curr-room-num-users"
).innerHTML = `${newNumberOfMembers} <span class="glyphicon glyphicon-user">`;
});
}
namespaces.js
// Bring in the room class
const Namespace = require('../classes/Namespace');
const Room = require('../classes/Room');
// Sets up the namespaces.
// Todo: create/populate namespaces and rooms from data stored in the DB.
// SYNTAX for new Namespace(id, nsTitle, img, endpoint)
let namespaces = [];
let wikiNs = new Namespace(0,'Wiki','https://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg/103px-Wikipedia-logo-v2.svg.png','/wiki');
let mozNs = new Namespace(1,'Mozilla','https://www.mozilla.org/media/img/logos/firefox/logo-quantum.9c5e96634f92.png','/mozilla');
let linuxNs = new Namespace(2,'Linux','https://upload.wikimedia.org/wikipedia/commons/a/af/Tux.png','/linux');
namespaces.push(wikiNs,mozNs,linuxNs);
// Make the main room and add it to rooms. it will ALWAYS be 0
// SYNTAX for new Room(roomId, roomTitle, namespace)
wikiNs.addRoom(new Room(0,'General','Wiki', true));
wikiNs.addRoom(new Room(1,'New Articles','Wiki', true));
wikiNs.addRoom(new Room(2,'Editors','Wiki'));
wikiNs.addRoom(new Room(3,'Other','Wiki'));
mozNs.addRoom(new Room(0,'General','Mozilla'));
mozNs.addRoom(new Room(1,'Firefox','Mozilla'));
mozNs.addRoom(new Room(2,'SeaMonkey','Mozilla'));
mozNs.addRoom(new Room(3,'SpiderMonkey','Mozilla'));
mozNs.addRoom(new Room(4,'Rust','Mozilla'));
linuxNs.addRoom(new Room(0,'General','Linux'));
linuxNs.addRoom(new Room(1,'Debian','Linux'));
linuxNs.addRoom(new Room(2,'Red Hat','Linux'));
linuxNs.addRoom(new Room(3,'MacOs','Linux'));
linuxNs.addRoom(new Room(4,'Kernal Development','Linux'));
module.exports = namespaces;
Namespace.js
class Namespace{
constructor(id, nsTitle, img, endpoint){
this.id=id;
this.img=img;
this.nsTitle=nsTitle;
this.endpoint=endpoint;
this.rooms = [];
}
addRoom(roomObj){
this.rooms.push(roomObj);
}
}
module.exports = Namespace;
Room.js
class Room{
constructor(roomId, roomTitle, namespace, privateRoom = false){
this.roomId=roomId;
this.roomTitle = roomTitle;
this.namespace = namespace;
this.privateRoom = privateRoom;
this.history = [];
}
addMessage(message){
this.history.push(message);
}
clearHistory(){
this.history = [];
}
}
module.exports = Room;
chat.html
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous"
/>
<link rel="stylesheet" type="text/css" href="./styles.css" />
<div class="container-fluid">
<div class="row">
<div class="col-sm-1 namespaces">
<!-- JS WILL UPDATE THIS DYNAMICALLY -->
</div>
<div class="col-sm-2 rooms">
<h3>Rooms</h3>
<ul class="room-list">
<!-- JS WILL UPDATE THIS DYNANIMICALLY -->
</ul>
</div>
<div class="chat-panel col-sm-9">
<div class="room-header row col-6">
<div class="col-sm-3">
<span class="curr-room-text">Current Room</span>
<span class="curr-room-num-users"
>Users <span class="glyphicon glyphicon-user"></span
></span>
</div>
<div class="col-sm-3 search pull-right">
<span class="glyphicon glyphicon-search"></span>
<input type="text" id="search-box" placeholder="Search" />
</div>
</div>
<div class="message-form">
<form id="user-input">
<div class="col-sm-12">
<input
id="user-message"
type="text"
placeholder="Enter your message"
/>
</div>
<!-- <div class="col-sm-2">
<input class="btn btn-primary" type="submit" value="send" />
</div> -->
</form>
</div>
<ul id="messages" class="col-sm-12">
<li>
<div class="user-image">
<img src="https://via.placeholder.com/30" />
</div>
<div class="user-message">
<div class="user-name-time">rbunch <span>1:25 pm</span></div>
<div class="message-text">I went running today.</div>
</div>
</li>
<li>
<div class="user-image">
<img src="https://via.placeholder.com/30" />
</div>
<div class="user-message">
<div class="user-name-time">rbunch <span>2:25 pm</span></div>
<div class="message-text">
I'm getting my tires changed this afternoon.
</div>
</div>
</li>
<li>
<div class="user-image">
<img src="https://via.placeholder.com/30" />
</div>
<div class="user-message">
<div class="user-name-time">rbunch <span>2:29 pm</span></div>
<div class="message-text">I like history.</div>
</div>
</li>
<li>
<div class="user-image">
<img src="https://via.placeholder.com/30" />
</div>
<div class="user-message">
<div class="user-name-time">rbunch <span>2:59 pm</span></div>
<div class="message-text">What day is tomorrow?.</div>
</div>
</li>
</ul>
</div>
</div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="/clientScripts.js"></script>
<script src="/joinNs.js"></script>
<script src="/joinRoom.js"></script>