diff --git a/frontend/src/pages/chat/chat.html b/frontend/src/pages/chat/chat.html index a087ef9..4c0698f 100644 --- a/frontend/src/pages/chat/chat.html +++ b/frontend/src/pages/chat/chat.html @@ -5,7 +5,7 @@ Chat Box
- +

Welcome,


diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index b112897..e0d51ee 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -6,173 +6,164 @@ 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, - transports: ["websocket"], -}); - -// Listen for the 'connect' event -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" -socket.on("MsgObjectServer", (data: any) => { - console.log("Message Obj Recieved:", data.message); - console.log("Recieved data.message.text: ", data.message.text); - console.log("Recieved data.message.user: ", data.message.user); - console.log("Recieved data.message.type: ", data.message.type); - console.log("Recieved data.message.token: ", data.message.token); - console.log("Recieved data.message.timestamp: ", data.message.timestamp); - - // Display the message in the chat window - const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement; - if (chatWindow) { - const messageElement = document.createElement("div"); - // 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; - } - console.log("Getuser():", getUser()); -}); - -type Providers = { - name: string, - display_name: string, - icon_url?: string, - color?: { default: string, hover: string }, -}; - -// function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { - - setTitle('Chat Page'); + const socket = io("wss://localhost:8888", { + path: "/api/chat/socket.io/", + secure: false, + transports: ["websocket"], + }); // Listen for the 'connect' event - return { - - html: authHtml, postInsert: async (app) => { - 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-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(); - if (value.kind === "success") { - console.log(value.payload); - } - else if (value.kind === "notLoggedIn") { - console.log('not logged in'); - } else { - console.log('unknown response: ', value); - } - - - const addMessage = (text: string) => { - if (!chatWindow) return; - const messageElement = document.createElement("div"); - messageElement.textContent = text; + 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" + socket.on("MsgObjectServer", (data: any) => { + console.log("Message Obj Recieved:", data.message); + console.log("Recieved data.message.text: ", data.message.text); + console.log("Recieved data.message.user: ", data.message.user); + console.log("Recieved data.message.type: ", data.message.type); + console.log("Recieved data.message.token: ", data.message.token); + console.log("Recieved data.message.timestamp: ", data.message.timestamp); + // Display the message in the chat window + const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement; + if (chatWindow) { + const messageElement = document.createElement("div"); + // 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; - }; + } + console.log("Getuser():", getUser()); + }); - // Send button - sendButton?.addEventListener("click",() => { - + type Providers = { + name: string, + display_name: string, + icon_url?: string, + color?: { default: string, hover: string }, + }; + + // function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { + + setTitle('Chat Page'); + // Listen for the 'connect' event + return { + + html: authHtml, postInsert: async (app) => { + 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-clear') as HTMLButtonElement; + const bwhoami = document.getElementById('b-whoami') as HTMLButtonElement; + const bconnected = document.getElementById('b-help') as HTMLButtonElement; + const username = document.getElementById('username') as HTMLDivElement; + + const value = await client.chatTest(); + if (value.kind === "success") { + console.log(value.payload); + } else if (value.kind === "notLoggedIn") { + console.log('not logged in'); + } else { + console.log('unknown response: ', value); + } - if (sendtextbox && sendtextbox.value.trim()) { - const msgText = sendtextbox.value.trim(); - - - - - addMessage(msgText); - - const user = getUser(); - if (user && socket?.connected) { - const message = { - type: "chat", - user: user.name, - token: document.cookie, - text: msgText, - timestamp: Date.now(), - SenderWindowID: socket.id, - }; - socket.send(JSON.stringify(message)); - } - sendtextbox.value = ""; - } - }); - - - // Clear Text button - clearText?.addEventListener("click", () => { - if (chatWindow) { - chatWindow.innerHTML = ''; - } - }); - - - // 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') { - sendButton?.click(); - } - }); - - // Whoami button to display user name - bwhoami?.addEventListener('click', async () => { - try { - const res = await client.guestLogin(); - switch (res.kind) { - case 'success': { - let user = await updateUser(); - if (user === null) - return showError('Failed to get user: no user ?'); - setTitle(`Welcome ${user.guest ? '[GUEST] ' : ''}${user.name}`); - break; - } - case 'failed': { - showError(`Failed to login: ${res.msg}`); - } + + const addMessage = (text: string) => { + if (!chatWindow) return; + const messageElement = document.createElement("div"); + messageElement.textContent = text; + chatWindow.appendChild(messageElement); + chatWindow.scrollTop = chatWindow.scrollHeight; + }; + + // Send button + sendButton?.addEventListener("click",() => { + if (sendtextbox && sendtextbox.value.trim()) { + const msgText = sendtextbox.value.trim(); + addMessage(msgText); + const user = getUser(); + if (user && socket?.connected) { + const message = { + type: "chat", + user: user.name, + token: document.cookie, + text: msgText, + timestamp: Date.now(), + SenderWindowID: socket.id, + }; + socket.send(JSON.stringify(message)); + } + sendtextbox.value = ""; + } + }); + + + // Clear Text button + clearText?.addEventListener("click", () => { + if (chatWindow) { + chatWindow.innerHTML = ''; } - } catch (e) { - console.error("Login error:", e); - showError('Failed to login: Unknown error'); - } - }); + }); + + + // Help Text button + bconnected?.addEventListener("click", async () => { + if (chatWindow) { + addMessage('@list - lists all connected users in the chat'); + await socket.emit('list'); + + socket.on('listObj', (list: string) => { + console.log('List chat clients connected ', list); + addMessage(list); + }); + } + }); + + + // Enter key to send message + sendtextbox!.addEventListener('keydown', (event) => { + if (event.key === 'Enter') { + sendButton?.click(); + } + }); + + // Whoami button to display user name + bwhoami?.addEventListener('click', async () => { + try { + const res = await client.guestLogin(); + switch (res.kind) { + case 'success': { + let user = await updateUser(); + if (user === null) + return showError('Failed to get user: no user ?'); + setTitle(`Welcome ${user.guest ? '[GUEST] ' : ''}${user.name}`); + break; + } + case 'failed': { + showError(`Failed to login: ${res.msg}`); + } + } + } catch (e) { + console.error("Login error:", e); + showError('Failed to login: Unknown error'); + } + }); } } }; diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index 24d9f6a..a0867be 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -6,7 +6,6 @@ import * as auth from '@shared/auth'; import * as swagger from '@shared/swagger'; import * as utils from '@shared/utils'; import { Server, Socket } from 'socket.io'; -import { Null } from '@sinclair/typebox'; declare const __SERVICE_NAME: string; @@ -27,10 +26,7 @@ const app: FastifyPluginAsync = async (fastify, opts): Promise => { await fastify.register(db.useDatabase as FastifyPluginAsync, {}); await fastify.register(auth.jwtPlugin as FastifyPluginAsync, {}); await fastify.register(auth.authPlugin as FastifyPluginAsync, {}); - // await fastify.register(useSocketIo, { - // path: '/api/chat/socket.io', - // }); - + // Place here your custom code! for (const plugin of Object.values(plugins)) { void fastify.register(plugin as FastifyPluginAsync, {}); @@ -79,51 +75,56 @@ declare module 'fastify' { async function onReady(fastify: FastifyInstance) { -function connectedUser(io?: Server): number { - let count = 0; - const seen = new Set(); // <- only log/count unique usernames + function connectedUser(io?: Server, target?: string): 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; - } + 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, "Chat Socket ID:", color.reset, 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); - // 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, "Chat Socket ID (unverified):", color.reset, socketId); - } + const targetSocketId: any = target; + io.to(targetSocketId).emit("listObj", username); - return count; -} + + console.log(color.yellow, "Chat 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, "Chat Socket ID (unverified):", color.reset, socketId); + } + + return count; + } function broadcast(data: ClientMessage, sender?: string) { @@ -131,8 +132,8 @@ function connectedUser(io?: Server): number { for (const s of sockets) { if (s.id !== sender) { - // Send REAL JSON object - + + // Send REAL JSON object const clientName = clientChat.get(s.id) || null; if (clientName !== null) { s.emit('MsgObjectServer', { message: data }); @@ -144,6 +145,7 @@ function connectedUser(io?: Server): number { } }); } + fastify.io.on('connection', (socket: Socket) => { socket.on('message', (message: string) => { console.info(color.blue, 'Socket connected!', color.reset, socket.id); @@ -153,6 +155,8 @@ function connectedUser(io?: Server): number { color.reset, message, ); + + const obj: ClientMessage = JSON.parse(message) as ClientMessage; clientChat.set(socket.id, obj.user); console.log( @@ -171,10 +175,23 @@ function connectedUser(io?: Server): number { console.log('testend received from client socket id:', sock_id_cl); }); - + socket.on('list', () => { + console.log(color.red, 'list activated', color.reset, socket.id); + connectedUser(fastify.io, socket.id); + + + }); + + + + socket.on("disconnecting", (reason) => { const clientName = clientChat.get(socket.id) || null; + console.log(color.green, `Client disconnecting: ${clientName} (${socket.id}) reason:`, reason); + if (reason === 'transport error') return; + + if (clientName !== null) { const obj = { type: "chat", @@ -186,8 +203,7 @@ function connectedUser(io?: Server): number { }; broadcast(obj, obj.SenderWindowID); - console.log(`Client disconnecting: ${clientName} (${socket.id}) reason:`, reason); - clientChat.delete(obj.user); + // clientChat.delete(obj.user); } }); });