added tab control to chat, When user leaves tab open on chat

This commit is contained in:
NigeParis 2025-11-26 14:41:21 +01:00
parent 40980bedeb
commit 422c0b26c4
9 changed files with 151 additions and 119 deletions

View file

@ -112,32 +112,6 @@
}
}
}
},
"500": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"failed"
]
},
"msg": {
"enum": [
"chat.failed.generic"
]
}
}
}
}
}
}
}
}

View file

@ -163,12 +163,10 @@ async function onReady(fastify: FastifyInstance) {
}
});
}
fastify.io.on('connection', (socket: Socket) => {
socket.on('message', (message: string) => {
console.info(
color.blue,
@ -191,6 +189,10 @@ async function onReady(fastify: FastifyInstance) {
color.reset,
`Sender: login name: "${obj.user}" - windowID "${obj.SenderWindowID}" - text message: "${obj.text}"`,
);
socket.emit('welcome', {
msg: `Welcome to the chat! `,
});
// Send object directly — DO NOT wrap it in a string
broadcast(obj, obj.SenderWindowID);
console.log(
@ -201,33 +203,35 @@ async function onReady(fastify: FastifyInstance) {
);
});
socket.emit("welcome", {
msg: `Welcome to the chat!`,
id: socket.id
});
socket.on('testend', (sock_id_cl: string) => {
console.log('testend received from client socket id:', sock_id_cl);
});
socket.on('wakeup', (message: string) => {
const obj: ClientMessage = JSON.parse(message) as ClientMessage;
clientChat.set(socket.id, { user: obj.user, lastSeen: Date.now() });
connectedUser(fastify.io),
console.log('Wakeup: ', message);
});
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;
const clientName = clientChat.get(socket.id)?.user|| null;
console.log(
color.green,
`Client disconnecting: ${clientName?.user} (${socket.id}) reason:`,
`Client disconnecting: ${clientName} (${socket.id}) reason:`,
reason,
);
if (reason === 'transport error') return;
if (clientName?.user !== null) {
if (clientName !== null) {
const obj = {
type: 'chat',
user: clientName!.user,
user: clientName,
token: '',
text: 'LEFT the chat',
timestamp: Date.now(),
@ -238,5 +242,70 @@ async function onReady(fastify: FastifyInstance) {
// clientChat.delete(obj.user);
}
});
socket.on('client_left', (reason) => {
const clientName = clientChat.get(socket.id)?.user|| null;
console.log(
color.green,
`Client left the Chat: ${clientName} (${socket.id}) reason:`,
reason,
);
if (reason === 'transport error') return;
if (clientName !== null) {
const obj = {
type: 'chat',
user: clientName,
token: '',
text: 'LEFT the chat but the window is still open',
timestamp: Date.now(),
SenderWindowID: socket.id,
};
console.log(obj.SenderWindowID);
broadcast(obj, obj.SenderWindowID);
// clientChat.delete(obj.user);
}
});
socket.on('client_entered', (data) => {
// data may be undefined (when frontend calls emit with no payload)
const userNameFromFrontend = data?.userName || null;
const userFromFrontend = data?.user || null;
let clientName = clientChat.get(socket.id)?.user || null;
const client = clientChat.get(socket.id) || null;
let text = 'is back in the chat';
// connectedUser(fastify.io, socket.id);
if(clientName === null) {console.log('ERROR: clientName is NULL'); return;};
if(client === null) {console.log('ERROR: client is NULL'); return;};
if (userNameFromFrontend !== userFromFrontend) {
text = `'is back in the chat, I used to be called '${userNameFromFrontend}`;
clientName = userFromFrontend;
if(clientName === null) {console.log('ERROR: clientName is NULL'); return;};
if (client) {
client.user = clientName;
}
}
console.log(
color.green,
`Client entered the Chat: ${clientName} (${socket.id})`
);
if (clientName !== null) {
const obj = {
type: 'chat',
user: clientName, // server-side stored name
frontendUserName: userNameFromFrontend, // from frontend
frontendUser: userFromFrontend, // from frontend
token: '',
text: text,
timestamp: Date.now(),
SenderWindowID: socket.id,
};
broadcast(obj, obj.SenderWindowID);
}
});
});
}

View file

@ -1294,32 +1294,6 @@
}
}
}
},
"500": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"failed"
]
},
"msg": {
"enum": [
"chat.failed.generic"
]
}
}
}
}
}
}
},
"tags": [

View file

@ -36,7 +36,7 @@
"vite": "^7.2.4"
},
"dependencies": {
"@redocly/cli": "^2.11.1",
"@redocly/cli": "^2.12.0",
"bindings": "^1.5.0"
}
}

46
src/pnpm-lock.yaml generated
View file

@ -9,8 +9,8 @@ importers:
.:
dependencies:
'@redocly/cli':
specifier: ^2.11.1
version: 2.11.1(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0)
specifier: ^2.12.0
version: 2.12.0(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0)
bindings:
specifier: ^1.5.0
version: 1.5.0
@ -946,27 +946,27 @@ packages:
'@redocly/ajv@8.17.1':
resolution: {integrity: sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==}
'@redocly/cli@2.11.1':
resolution: {integrity: sha512-doNs+sdrFzzXmyf1yIeJbPh8OChacHWkvTE9N0QbuCmnYQ4k0v1IMP20qsitkwR+fK8O1hXSnFnSTVvIunMVVw==}
'@redocly/cli@2.12.0':
resolution: {integrity: sha512-/q8RnBe+Duo+XYFCG8LnaD0kroGZ8MoS6575Xq59tCgjaCL16F+pZZ75xNBU2oXfEypJClNz/6ilc2G0q1+tlw==}
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
hasBin: true
'@redocly/config@0.22.2':
resolution: {integrity: sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==}
'@redocly/config@0.38.0':
resolution: {integrity: sha512-kSgMG3rRzgXIP/6gWMRuWbu9/ms0Cyuphcx19dPR9qlgc1tt9IKYPsFQ+KhJuEtqd3bcY/+Uflysf33dQkZWVQ==}
'@redocly/config@0.40.0':
resolution: {integrity: sha512-MZQZs7QEGnue3rVN9Q9QvDbcGjesxbpKXUvDeckS69R1xjtgsnT9B39VA25zmwSJtgUeA9ST+sMf9GxIqixNbw==}
'@redocly/openapi-core@1.34.5':
resolution: {integrity: sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==}
engines: {node: '>=18.17.0', npm: '>=9.5.0'}
'@redocly/openapi-core@2.11.1':
resolution: {integrity: sha512-FVCDnZxaoUJwLQxfW4inCojxUO56J3ntu7dDAE2qyWd6tJBK45CnXMQQUxpqeRTeXROr3jYQoApAw+GCEnyBeg==}
'@redocly/openapi-core@2.12.0':
resolution: {integrity: sha512-RsVwmRD0KhyJbR8acIeU98ce6N+/YCuLJf6IGN+2SOsbwnDhnI5MG0TFV9D7URK/ukEewaNA701dVYsoP1VtRQ==}
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
'@redocly/respect-core@2.11.1':
resolution: {integrity: sha512-jSMJvCJeo5gmhQfg82AhuwCG0h8gbW5vqHyRITBu8KHVsBiQTgvfhXepu8SKHeJu0OexYtEc0nUnGLJlefevYw==}
'@redocly/respect-core@2.12.0':
resolution: {integrity: sha512-mrYrfE81shSRS96ygXaRiSithV4Fe4Y7XlSYLSTfM8Lo3YAz7Geirg7HZ5fNFsI+hdW05ZuQewqpKL8XLwaAeA==}
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
'@rollup/rollup-android-arm-eabi@4.53.3':
@ -1483,8 +1483,8 @@ packages:
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
engines: {node: '>= 0.6'}
cookie@1.0.2:
resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
cookie@1.1.0:
resolution: {integrity: sha512-vXiThu1/rlos7EGu8TuNZQEg2e9TvhH9dmS4T4ZVzB7Ao1agEZ6EG3sn5n+hZRYUgduISd1HpngFzAZiDGm5vQ==}
engines: {node: '>=18'}
core-js@3.47.0:
@ -3436,7 +3436,7 @@ snapshots:
'@fastify/cookie@11.0.2':
dependencies:
cookie: 1.0.2
cookie: 1.1.0
fastify-plugin: 5.1.0
'@fastify/deepmerge@3.1.0': {}
@ -3873,14 +3873,14 @@ snapshots:
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
'@redocly/cli@2.11.1(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0)':
'@redocly/cli@2.12.0(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0)':
dependencies:
'@opentelemetry/exporter-trace-otlp-http': 0.202.0(@opentelemetry/api@1.9.0)
'@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-trace-node': 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/semantic-conventions': 1.34.0
'@redocly/openapi-core': 2.11.1(ajv@8.17.1)
'@redocly/respect-core': 2.11.1(ajv@8.17.1)
'@redocly/openapi-core': 2.12.0(ajv@8.17.1)
'@redocly/respect-core': 2.12.0(ajv@8.17.1)
abort-controller: 3.0.0
chokidar: 3.6.0
colorette: 1.4.0
@ -3913,7 +3913,7 @@ snapshots:
'@redocly/config@0.22.2': {}
'@redocly/config@0.38.0':
'@redocly/config@0.40.0':
dependencies:
json-schema-to-ts: 2.7.2
@ -3931,10 +3931,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@redocly/openapi-core@2.11.1(ajv@8.17.1)':
'@redocly/openapi-core@2.12.0(ajv@8.17.1)':
dependencies:
'@redocly/ajv': 8.17.1
'@redocly/config': 0.38.0
'@redocly/config': 0.40.0
ajv-formats: 2.1.1(ajv@8.17.1)
colorette: 1.4.0
js-levenshtein: 1.1.6
@ -3945,12 +3945,12 @@ snapshots:
transitivePeerDependencies:
- ajv
'@redocly/respect-core@2.11.1(ajv@8.17.1)':
'@redocly/respect-core@2.12.0(ajv@8.17.1)':
dependencies:
'@faker-js/faker': 7.6.0
'@noble/hashes': 1.8.0
'@redocly/ajv': 8.11.4
'@redocly/openapi-core': 2.11.1(ajv@8.17.1)
'@redocly/openapi-core': 2.12.0(ajv@8.17.1)
better-ajv-errors: 1.2.0(ajv@8.17.1)
colorette: 2.0.20
json-pointer: 0.6.2
@ -4448,7 +4448,7 @@ snapshots:
cookie@0.7.2: {}
cookie@1.0.2: {}
cookie@1.1.0: {}
core-js@3.47.0: {}
@ -5167,7 +5167,7 @@ snapshots:
light-my-request@6.6.0:
dependencies:
cookie: 1.0.2
cookie: 1.1.0
process-warning: 4.0.1
set-cookie-parser: 2.7.2