mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-10 15:37:58 -05:00
docs(examples): 2nd part of the "private messaging" example
See also: https://socket.io/get-started/private-messaging-part-2/
This commit is contained in:
@@ -5,43 +5,91 @@ const io = require("socket.io")(httpServer, {
|
||||
},
|
||||
});
|
||||
|
||||
const crypto = require("crypto");
|
||||
const randomId = () => crypto.randomBytes(8).toString("hex");
|
||||
|
||||
const { InMemorySessionStore } = require("./sessionStore");
|
||||
const sessionStore = new InMemorySessionStore();
|
||||
|
||||
io.use((socket, next) => {
|
||||
const sessionID = socket.handshake.auth.sessionID;
|
||||
if (sessionID) {
|
||||
const session = sessionStore.findSession(sessionID);
|
||||
if (session) {
|
||||
socket.sessionID = sessionID;
|
||||
socket.userID = session.userID;
|
||||
socket.username = session.username;
|
||||
return next();
|
||||
}
|
||||
}
|
||||
const username = socket.handshake.auth.username;
|
||||
if (!username) {
|
||||
return next(new Error("invalid username"));
|
||||
}
|
||||
socket.sessionID = randomId();
|
||||
socket.userID = randomId();
|
||||
socket.username = username;
|
||||
next();
|
||||
});
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
// persist session
|
||||
sessionStore.saveSession(socket.sessionID, {
|
||||
userID: socket.userID,
|
||||
username: socket.username,
|
||||
connected: true,
|
||||
});
|
||||
|
||||
// emit session details
|
||||
socket.emit("session", {
|
||||
sessionID: socket.sessionID,
|
||||
userID: socket.userID,
|
||||
});
|
||||
|
||||
// join the "userID" room
|
||||
socket.join(socket.userID);
|
||||
|
||||
// fetch existing users
|
||||
const users = [];
|
||||
for (let [id, socket] of io.of("/").sockets) {
|
||||
sessionStore.findAllSessions().forEach((session) => {
|
||||
users.push({
|
||||
userID: id,
|
||||
username: socket.username,
|
||||
userID: session.userID,
|
||||
username: session.username,
|
||||
connected: session.connected,
|
||||
});
|
||||
}
|
||||
});
|
||||
socket.emit("users", users);
|
||||
|
||||
// notify existing users
|
||||
socket.broadcast.emit("user connected", {
|
||||
userID: socket.id,
|
||||
userID: socket.userID,
|
||||
username: socket.username,
|
||||
connected: true,
|
||||
});
|
||||
|
||||
// forward the private message to the right recipient
|
||||
// forward the private message to the right recipient (and to other tabs of the sender)
|
||||
socket.on("private message", ({ content, to }) => {
|
||||
socket.to(to).emit("private message", {
|
||||
socket.to(to).to(socket.userID).emit("private message", {
|
||||
content,
|
||||
from: socket.id,
|
||||
from: socket.userID,
|
||||
to,
|
||||
});
|
||||
});
|
||||
|
||||
// notify users upon disconnection
|
||||
socket.on("disconnect", () => {
|
||||
socket.broadcast.emit("user disconnected", socket.id);
|
||||
socket.on("disconnect", async () => {
|
||||
const matchingSockets = await io.in(socket.userID).allSockets();
|
||||
const isDisconnected = matchingSockets.size === 0;
|
||||
if (isDisconnected) {
|
||||
// notify other users
|
||||
socket.broadcast.emit("user disconnected", socket.userID);
|
||||
// update the connection status of the session
|
||||
sessionStore.saveSession(socket.sessionID, {
|
||||
userID: socket.userID,
|
||||
username: socket.username,
|
||||
connected: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
28
examples/private-messaging/server/sessionStore.js
Normal file
28
examples/private-messaging/server/sessionStore.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/* abstract */ class SessionStore {
|
||||
findSession(id) {}
|
||||
saveSession(id, session) {}
|
||||
findAllSessions() {}
|
||||
}
|
||||
|
||||
class InMemorySessionStore extends SessionStore {
|
||||
constructor() {
|
||||
super();
|
||||
this.sessions = new Map();
|
||||
}
|
||||
|
||||
findSession(id) {
|
||||
return this.sessions.get(id);
|
||||
}
|
||||
|
||||
saveSession(id, session) {
|
||||
this.sessions.set(id, session);
|
||||
}
|
||||
|
||||
findAllSessions() {
|
||||
return [...this.sessions.values()];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
InMemorySessionStore
|
||||
};
|
||||
@@ -32,6 +32,23 @@ export default {
|
||||
},
|
||||
},
|
||||
created() {
|
||||
const sessionID = localStorage.getItem("sessionID");
|
||||
|
||||
if (sessionID) {
|
||||
this.usernameAlreadySelected = true;
|
||||
socket.auth = { sessionID };
|
||||
socket.connect();
|
||||
}
|
||||
|
||||
socket.on("session", ({ sessionID, userID }) => {
|
||||
// attach the session ID to the next reconnection attempts
|
||||
socket.auth = { sessionID };
|
||||
// store it in the localStorage
|
||||
localStorage.setItem("sessionID", sessionID);
|
||||
// save the ID of the user
|
||||
socket.userID = userID;
|
||||
});
|
||||
|
||||
socket.on("connect_error", (err) => {
|
||||
if (err.message === "invalid username") {
|
||||
this.usernameAlreadySelected = false;
|
||||
|
||||
@@ -68,18 +68,25 @@ export default {
|
||||
});
|
||||
|
||||
const initReactiveProperties = (user) => {
|
||||
user.connected = true;
|
||||
user.messages = [];
|
||||
user.hasNewMessages = false;
|
||||
};
|
||||
|
||||
socket.on("users", (users) => {
|
||||
users.forEach((user) => {
|
||||
user.self = user.userID === socket.id;
|
||||
for (let i = 0; i < this.users.length; i++) {
|
||||
const existingUser = this.users[i];
|
||||
if (existingUser.userID === user.userID) {
|
||||
existingUser.connected = user.connected;
|
||||
return;
|
||||
}
|
||||
}
|
||||
user.self = user.userID === socket.userID;
|
||||
initReactiveProperties(user);
|
||||
this.users.push(user);
|
||||
});
|
||||
// put the current user first, and sort by username
|
||||
this.users = users.sort((a, b) => {
|
||||
this.users.sort((a, b) => {
|
||||
if (a.self) return -1;
|
||||
if (b.self) return 1;
|
||||
if (a.username < b.username) return -1;
|
||||
@@ -88,6 +95,13 @@ export default {
|
||||
});
|
||||
|
||||
socket.on("user connected", (user) => {
|
||||
for (let i = 0; i < this.users.length; i++) {
|
||||
const existingUser = this.users[i];
|
||||
if (existingUser.userID === user.userID) {
|
||||
existingUser.connected = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
initReactiveProperties(user);
|
||||
this.users.push(user);
|
||||
});
|
||||
@@ -102,13 +116,14 @@ export default {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("private message", ({ content, from }) => {
|
||||
socket.on("private message", ({ content, from, to }) => {
|
||||
for (let i = 0; i < this.users.length; i++) {
|
||||
const user = this.users[i];
|
||||
if (user.userID === from) {
|
||||
const fromSelf = socket.userID === from;
|
||||
if (user.userID === (fromSelf ? to : from)) {
|
||||
user.messages.push({
|
||||
content,
|
||||
fromSelf: false,
|
||||
fromSelf,
|
||||
});
|
||||
if (user !== this.selectedUser) {
|
||||
user.hasNewMessages = true;
|
||||
|
||||
Reference in New Issue
Block a user