From 5031efa8661c5c3e820fc8d71a074d4e370233ac Mon Sep 17 00:00:00 2001 From: NigeParis Date: Mon, 24 Nov 2025 11:18:32 +0100 Subject: [PATCH] Add Arrived in Chat and Left in chat LoginName --- frontend/src/pages/chat/chat.html | 3 +- frontend/src/pages/chat/chat.ts | 48 +++++++--- frontend/src/pages/chat/socket_client.ts | 48 ---------- src/chat/src/app.ts | 108 +++++++++++++++++------ src/chat/src/routes/nginx-chat.ts | 2 +- 5 files changed, 123 insertions(+), 86 deletions(-) delete mode 100644 frontend/src/pages/chat/socket_client.ts diff --git a/frontend/src/pages/chat/chat.html b/frontend/src/pages/chat/chat.html index 48445b8..a087ef9 100644 --- a/frontend/src/pages/chat/chat.html +++ b/frontend/src/pages/chat/chat.html @@ -4,7 +4,8 @@

Chat Box


- + +

Welcome,


diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 012c68c..b112897 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -5,6 +5,7 @@ import client from '@app/api' import { getUser, updateUser } from "@app/auth"; import io from 'socket.io-client'; +function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { const socket = io("wss://localhost:8888", { path: "/api/chat/socket.io/", secure: false, @@ -12,13 +13,23 @@ const socket = io("wss://localhost:8888", { }); // Listen for the 'connect' event -socket.on("connect", async () => { - console.log("I AM Connected to the server: ", socket.id); - // Emit a custom event 'coucou' with some data - //socket.emit("coucou", { message: " Nigel from coucou!" }); - //socket.emit('testend', socket.id); - // Send a message to the server - //socket.send(" from the client: " + `${socket.id}`); +socket.on("connect", () => { + console.log("I AM Connected to the server:", socket.id); + + const user = getUser()?.name; + + // Ensure we have a user AND socket is connected + if (!user || !socket.connected) return; + + const message = { + type: "chat", + user, + token: document.cookie ?? "", + text: " has Just ARRIVED in the chat", + timestamp: Date.now(), + SenderWindowID: socket.id, + }; + socket.emit('message', JSON.stringify(message)); }); // Listen for messages from the server "MsgObjectServer" @@ -34,7 +45,13 @@ socket.on("MsgObjectServer", (data: any) => { const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement; if (chatWindow) { const messageElement = document.createElement("div"); - messageElement.textContent = `${data.message.user}: ${data.message.text}`; + // if (getUser()?.id !== `${data.message.id}`) { + console.log('==================> HERE'); + messageElement.textContent = `${data.message.user}: ${data.message.text}`; + // } else { + // console.log('==================>AND HERE'); + // messageElement.textContent = `here`; + // } chatWindow.appendChild(messageElement); chatWindow.scrollTop = chatWindow.scrollHeight; } @@ -48,7 +65,7 @@ type Providers = { color?: { default: string, hover: string }, }; -function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { +// function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { setTitle('Chat Page'); // Listen for the 'connect' event @@ -58,8 +75,9 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn const sendButton = document.getElementById('b-send') as HTMLButtonElement; const chatWindow = document.getElementById('t-chatbox') as HTMLDivElement; const sendtextbox = document.getElementById('t-chat-window') as HTMLButtonElement; - const clearText = document.getElementById('b-logout') as HTMLButtonElement; + const clearText = document.getElementById('b-clear') as HTMLButtonElement; const bwhoami = document.getElementById('b-whoami') as HTMLButtonElement; + const bhelp = document.getElementById('b-help') as HTMLButtonElement; const username = document.getElementById('username') as HTMLDivElement; const value = await client.chatTest(); @@ -117,6 +135,16 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn } }); + + // Help Text button + bhelp?.addEventListener("click", () => { + if (chatWindow) { + addMessage('@Help - List Chat Commands:'); + addMessage('@list - lists all user connected'); + } + }); + + // Enter key to send message sendtextbox!.addEventListener('keydown', (event) => { if (event.key === 'Enter') { diff --git a/frontend/src/pages/chat/socket_client.ts b/frontend/src/pages/chat/socket_client.ts deleted file mode 100644 index b033fd7..0000000 --- a/frontend/src/pages/chat/socket_client.ts +++ /dev/null @@ -1,48 +0,0 @@ -////WORKING ON THE SEPARATE NONO FUCTIONNELING SOCKET CLIENT TO BE IMPORTED INTO CHAT.TS//// - -// import io from "socket.io-client"; - -// // const socket = io("wss://localhost:8888"); - -// export const socket = io("wss://localhost:8888", { -// path: "/api/chat/socket.io/", -// secure: false, -// transports: ["websocket"], -// }); - -// // Listen for the 'connect' event -// socket.on("connect", async () => { -// console.log("I AM Connected to the server: ", socket.id); -// // Emit a custom event 'coucou' with some data -// socket.emit("MsgObjectClient", { message: " Nigel from coucou!" }); -// console.log('sent console.log coucou'); -// // Send a message to the server -// socket.send(" from the client: " + `${socket.id}`); -// console.log("MESSAGE REPLY RETURNED FROM SERVER =====>: ", socket.emit("", {: " Nigel from coucou!"}).id); -// }); - - -// // Listen for messages from the server -// socket.on("MsgObjectServer", (data) => { -// console.log("Message from server:", data); -// }); - -// socket.on("", (data) => { -// console.log("MESSAGE REPLY RETURNED FROM SERVER =====>:", data); -// }); - - -// // Disconnected -// socket.on("disconnect", (reason) => { -// console.log("Socket disconnected:", reason); -// }); - -// // Socket.IO connection errors -// socket.on("connect_error", (err) => { -// console.error("Connection error:", err.message); -// }); - -// // Server-side errors -// socket.on("error", (err) => { -// console.error("Socket error:", err); -// }); diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index 3a479b5..0f6ab42 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -9,6 +9,9 @@ import { Server, Socket } from 'socket.io'; declare const __SERVICE_NAME: string; +// Global map of clients +const clientChat = new Map(); // key = client name, value = socket + // @ts-expect-error: import.meta.glob is a vite thing. Typescript doesn't know this... const plugins = import.meta.glob('./plugins/**/*.ts', { eager: true }); // @ts-expect-error: import.meta.glob is a vite thing. Typescript doesn't know this... @@ -55,7 +58,7 @@ export const color = { }; type ClientMessage = { - userID: string; + user: string; text: string; SenderWindowID: string; }; @@ -73,36 +76,73 @@ declare module 'fastify' { } async function onReady(fastify: FastifyInstance) { - // Broadcast function to send messages to all connected clients except the sender + + +function connectedUser(io?: Server): number { + let count = 0; + const seen = new Set(); // <- only log/count unique usernames + + for (const [socketId, username] of clientChat) { + // Basic sanity checks + if (typeof socketId !== "string" || socketId.length === 0) { + clientChat.delete(socketId); + continue; + } + if (typeof username !== "string" || username.length === 0) { + clientChat.delete(socketId); + continue; + } + + // If we have the io instance, attempt to validate the socket is still connected + if (io && typeof io.sockets?.sockets?.get === "function") { + const s = io.sockets.sockets.get(socketId) as Socket | undefined; + // If socket not found or disconnected, remove from map and skip + if (!s || s.disconnected) { + clientChat.delete(socketId); + continue; + } + + // Skip duplicates (DO NOT delete them — just don't count) + if (seen.has(username)) { + continue; + } + // socket exists and is connected + seen.add(username); + count++; + // console.log(color.green,"count: ", count); + console.log(color.yellow, "Client:", color.reset, username); + console.log(color.yellow, "Socket ID:", color.reset, socketId); + continue; + } + + // If no io provided, assume entries in the map are valid and count them. + count++; + console.log(color.red, "Client (unverified):", color.reset, username); + console.log(color.red, "Socket ID (unverified):", color.reset, socketId); + } + + return count; +} + + function broadcast(data: ClientMessage, sender?: string) { fastify.io.fetchSockets().then((sockets) => { - console.log('Connected clients:', sockets.length); for (const s of sockets) { if (s.id !== sender) { // Send REAL JSON object s.emit('MsgObjectServer', { message: data }); - console.log(' emit window socket ID:', s.id); - console.log(' emit window ID:', [...s.rooms]); + console.log(' Target window socket ID:', s.id); + console.log(' Target window ID:', [...s.rooms]); console.log(' Sender window ID:', sender ? sender : 'none'); - console.log( - ' text recieved:', - data.text ? data.text : 'none', - ); - console.log( - color.red, - 'data:', - color.reset, - data ? data : 'none', - ); } } }); } fastify.io.on('connection', (socket: Socket) => { - console.info(color.blue, 'Socket connected!', color.reset, socket.id); socket.on('message', (message: string) => { + console.info(color.blue, 'Socket connected!', color.reset, socket.id); console.log( color.blue, 'Received message from client', @@ -110,27 +150,43 @@ async function onReady(fastify: FastifyInstance) { message, ); const obj: ClientMessage = JSON.parse(message) as ClientMessage; + clientChat.set(socket.id, obj.user); console.log( color.green, 'Message from client', color.reset, - `${obj.userID}: ${obj.text}`, + `Sender: login name: "${obj.user}" - windowID "${obj.SenderWindowID}" - text message: "${obj.text}"`, ); - // Send object directly — DO NOT wrap it in a string broadcast(obj, obj.SenderWindowID); + connectedUser(fastify.io); }); + + socket.on('testend', (sock_id_cl: string) => { console.log('testend received from client socket id:', sock_id_cl); }); - socket.on('disconnecting', (reason) => { - console.log( - 'Client is disconnecting:', - socket.id, - 'reason:', - reason, - ); - console.log('Socket AAAAAAAActing because:', socket.connected); + + + socket.on("disconnecting", (reason) => { + + const clientName = clientChat.get(socket.id) || "Unknown"; + + const obj = { + type: "chat", + user: clientName, + token: "", + text: `LEFT the chat`, + timestamp: Date.now(), + SenderWindowID: socket.id, + }; + + broadcast(obj, obj.SenderWindowID); + + console.log(`Client disconnecting: ${clientName} (${socket.id}) reason:`, reason); + + // Remove from map + clientChat.delete(socket.id); }); }); } diff --git a/src/chat/src/routes/nginx-chat.ts b/src/chat/src/routes/nginx-chat.ts index d2f45ef..1358728 100644 --- a/src/chat/src/routes/nginx-chat.ts +++ b/src/chat/src/routes/nginx-chat.ts @@ -23,7 +23,7 @@ const route: FastifyPluginAsync = async (fastify): Promise => { config: { requireAuth: true }, }, async (req, res) => { - console.log('/api/chat called =================>'); + //console.log('/api/chat/test called =================>'); res.makeResponse(200, 'success', 'CCChat.success', { name: 'My_namw', 'id': req.authUser!.id, guest: false }); }, );