feat(chat): updated to work with socket.io
- Chore: ran `make npm@update` to update deps and lockfile - Chat: new plugin: Socket.ts that allow the use of socket.io with fastify (fastify-socket.io is not updated) - Chat: Put everything from `src/socket.ts` that needed to be saved into `src/app.ts`
This commit is contained in:
parent
6ff1745f16
commit
eec27ce2e6
9 changed files with 132 additions and 143 deletions
|
|
@ -18,9 +18,9 @@
|
|||
"better-sqlite3": "^11.10.0",
|
||||
"fastify": "^5.6.2",
|
||||
"fastify-plugin": "^5.1.0",
|
||||
"joi": "^18.0.1",
|
||||
"joi": "^18.0.2",
|
||||
"otp": "^1.1.2",
|
||||
"typebox": "^1.0.53",
|
||||
"typebox": "^1.0.55",
|
||||
"uuidv7": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@
|
|||
"fastify": "^5.6.2",
|
||||
"fastify-cli": "^7.4.1",
|
||||
"fastify-plugin": "^5.1.0",
|
||||
"typebox": "^1.0.53"
|
||||
"typebox": "^1.0.55"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.19.1",
|
||||
"rollup-plugin-node-externals": "^8.1.2",
|
||||
"vite": "^7.2.2",
|
||||
"vite": "^7.2.4",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,15 +26,13 @@
|
|||
"@fastify/websocket": "^11.2.0",
|
||||
"@sinclair/typebox": "^0.34.41",
|
||||
"fastify": "^5.6.2",
|
||||
"fastify-cli": "^7.4.1",
|
||||
"fastify-plugin": "^5.1.0",
|
||||
"fastify-socket.io": "^5.1.0",
|
||||
"socket.io": "^4.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.19.1",
|
||||
"rollup-plugin-node-externals": "^8.1.2",
|
||||
"vite": "^7.2.2",
|
||||
"vite": "^7.2.4",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
import { FastifyPluginAsync } from 'fastify';
|
||||
import { FastifyInstance, FastifyPluginAsync } from 'fastify';
|
||||
import fastifyFormBody from '@fastify/formbody';
|
||||
import fastifyMultipart from '@fastify/multipart';
|
||||
import * as db from '@shared/database';
|
||||
import * as auth from '@shared/auth';
|
||||
import * as swagger from '@shared/swagger';
|
||||
import * as utils from '@shared/utils';
|
||||
// import useSocketIo from 'fastify-socket.io';
|
||||
import { setupSocketIo } from './socket';
|
||||
import.meta.glob('/plugins/**.ts')
|
||||
|
||||
import { Server, Socket } from 'socket.io';
|
||||
|
||||
declare const __SERVICE_NAME: string;
|
||||
|
||||
|
|
@ -19,6 +16,8 @@ const routes = import.meta.glob('./routes/**/*.ts', { eager: true });
|
|||
|
||||
const app: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
|
||||
void opts;
|
||||
|
||||
await fastify.register(utils.useMonitoring);
|
||||
await fastify.register(utils.useMakeResponse);
|
||||
await fastify.register(swagger.useSwagger, { service: __SERVICE_NAME });
|
||||
await fastify.register(db.useDatabase as FastifyPluginAsync, {});
|
||||
|
|
@ -38,13 +37,100 @@ const app: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
|
|||
|
||||
void fastify.register(fastifyFormBody, {});
|
||||
void fastify.register(fastifyMultipart, {});
|
||||
fastify.get('/monitoring', () => 'Ok');
|
||||
|
||||
|
||||
|
||||
|
||||
// Setup Socket.io
|
||||
setupSocketIo();
|
||||
fastify.ready((err) => {
|
||||
if (err) throw err;
|
||||
onReady(fastify);
|
||||
});
|
||||
};
|
||||
export default app;
|
||||
export { app };
|
||||
|
||||
export const color = {
|
||||
red: 'x1b[31m',
|
||||
green: 'x1b[32m',
|
||||
yellow: 'x1b[33m',
|
||||
blue: 'x1b[34m',
|
||||
reset: 'x1b[0m',
|
||||
};
|
||||
|
||||
type ClientMessage = {
|
||||
userID: string;
|
||||
text: string;
|
||||
SenderWindowID: string;
|
||||
};
|
||||
|
||||
// When using .decorate you have to specify added properties for Typescript
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
io: Server<{
|
||||
hello: (message: string) => string;
|
||||
MsgObjectServer: (data: { message: ClientMessage }) => void;
|
||||
message: (msg: string) => void;
|
||||
testend: (sock_id_client: string) => void;
|
||||
}>;
|
||||
}
|
||||
}
|
||||
|
||||
async function onReady(fastify: FastifyInstance) {
|
||||
// Broadcast function to send messages to all connected clients except the sender
|
||||
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(' 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.log(
|
||||
color.blue,
|
||||
'Received message from client',
|
||||
color.reset,
|
||||
message,
|
||||
);
|
||||
const obj: ClientMessage = JSON.parse(message) as ClientMessage;
|
||||
console.log(
|
||||
color.green,
|
||||
'Message from client',
|
||||
color.reset,
|
||||
`${obj.userID}: ${obj.text}`,
|
||||
);
|
||||
|
||||
// Send object directly — DO NOT wrap it in a string
|
||||
broadcast(obj, obj.SenderWindowID);
|
||||
});
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,31 @@
|
|||
import type {
|
||||
FastifyInstance,
|
||||
FastifyPluginAsync,
|
||||
HookHandlerDoneFunction,
|
||||
FastifyInstance,
|
||||
FastifyPluginAsync,
|
||||
HookHandlerDoneFunction,
|
||||
} from 'fastify';
|
||||
import fp from 'fastify-plugin';
|
||||
import { Server, type ServerOptions } from 'socket.io';
|
||||
import { Server } from 'socket.io';
|
||||
|
||||
export type FastifySocketioOptions = Partial<ServerOptions> & {
|
||||
preClose?: (done: HookHandlerDoneFunction) => void;
|
||||
};
|
||||
const F: (
|
||||
f: FastifyInstance,
|
||||
) => Omit<FastifyInstance, 'io'> & { io: Server } = (f) =>
|
||||
f as Omit<FastifyInstance, 'io'> & { io: Server };
|
||||
|
||||
const F: (f: FastifyInstance) => (Omit<FastifyInstance, 'io'> & { io: Server }) = f => (f as Omit<FastifyInstance, 'io'> & { io: Server });
|
||||
const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
||||
function defaultPreClose(done: HookHandlerDoneFunction) {
|
||||
F(fastify).io.local.disconnectSockets(true);
|
||||
done();
|
||||
}
|
||||
fastify.decorate(
|
||||
'io',
|
||||
new Server(fastify.server, { path: '/api/chat/socket.io' }),
|
||||
);
|
||||
fastify.addHook('preClose', defaultPreClose);
|
||||
fastify.addHook('onClose', (instance: FastifyInstance, done) => {
|
||||
F(instance).io.close();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
const fastifySocketIO: FastifyPluginAsync<FastifySocketioOptions> = fp(
|
||||
async (fastify, opts: FastifySocketioOptions) => {
|
||||
function defaultPreClose(done: HookHandlerDoneFunction) {
|
||||
F(fastify).io.local.disconnectSockets(true);
|
||||
done();
|
||||
}
|
||||
fastify.decorate('io', new Server(fastify.server, opts));
|
||||
fastify.addHook('preClose', (done) => {
|
||||
if (opts.preClose) {
|
||||
return opts.preClose(done);
|
||||
}
|
||||
return defaultPreClose(done);
|
||||
});
|
||||
fastify.addHook('onClose', (instance: FastifyInstance, done) => {
|
||||
F(instance).io.close();
|
||||
done();
|
||||
});
|
||||
},
|
||||
);
|
||||
export default fastifySocketIO;
|
||||
|
||||
|
||||
export default fastifySocketIO;
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
import Fastify from "fastify";
|
||||
import { Server, Socket } from 'socket.io';
|
||||
|
||||
export const color = {
|
||||
red: 'x1b[31m',
|
||||
green: 'x1b[32m',
|
||||
yellow: 'x1b[33m',
|
||||
blue: 'x1b[34m',
|
||||
reset: 'x1b[0m',
|
||||
};
|
||||
|
||||
type ClientMessage = {
|
||||
userID: string;
|
||||
text: string;
|
||||
SenderWindowID: string;
|
||||
};
|
||||
|
||||
// When using .decorate you have to specify added properties for Typescript
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
io: Server<{
|
||||
hello: (message: string) => string,
|
||||
MsgObjectServer: (data: { message: ClientMessage }) => void,
|
||||
message: (msg: string) => void,
|
||||
testend: (sock_id_client: string) => void,
|
||||
}>
|
||||
}
|
||||
};
|
||||
|
||||
const fastify = Fastify({
|
||||
logger: true
|
||||
});
|
||||
|
||||
|
||||
export async function setupSocketIo() {
|
||||
// Wait for Fastify to be ready so .server exists
|
||||
await fastify.ready();
|
||||
|
||||
const io = new Server(fastify.server, {
|
||||
cors: {
|
||||
origin: "*"
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// export function setupSocketIo(fastify: import('fastify').FastifyInstance): void {
|
||||
|
||||
// fastify.ready((err) => {
|
||||
// if (err) throw err;
|
||||
|
||||
// Broadcast function to send messages to all connected clients except the sender
|
||||
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(' 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');
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(fastify.io)));
|
||||
io.on('connection', (socket : Socket) => {
|
||||
console.info(color.blue, 'Socket connected!', color.reset, socket.id);
|
||||
socket.on('message', (message: string) => {
|
||||
console.log(color.blue, 'Received message from client', color.reset, message);
|
||||
const obj: ClientMessage = JSON.parse(message) as ClientMessage;
|
||||
console.log(color.green, 'Message from client', color.reset, `${obj.userID}: ${obj.text}`);
|
||||
|
||||
// Send object directly — DO NOT wrap it in a string
|
||||
broadcast(obj, obj.SenderWindowID);
|
||||
});
|
||||
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);
|
||||
});
|
||||
});
|
||||
// });
|
||||
};
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
"devDependencies": {
|
||||
"@types/node": "^22.19.1",
|
||||
"rollup-plugin-node-externals": "^8.1.2",
|
||||
"vite": "^7.2.2",
|
||||
"vite": "^7.2.4",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,17 +23,17 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@openapitools/openapi-generator-cli": "^2.25.1",
|
||||
"@openapitools/openapi-generator-cli": "^2.25.2",
|
||||
"@typescript-eslint/eslint-plugin": "^8.47.0",
|
||||
"@typescript-eslint/parser": "^8.47.0",
|
||||
"eslint": "^9.39.1",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.2.6",
|
||||
"lint-staged": "^16.2.7",
|
||||
"openapi-generator-cli": "^1.0.0",
|
||||
"openapi-typescript": "^7.10.1",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.47.0",
|
||||
"vite": "^7.2.2"
|
||||
"vite": "^7.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@redocly/cli": "^2.11.1",
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@
|
|||
"fastify": "^5.6.2",
|
||||
"fastify-cli": "^7.4.1",
|
||||
"fastify-plugin": "^5.1.0",
|
||||
"typebox": "^1.0.53"
|
||||
"typebox": "^1.0.55"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.19.1",
|
||||
"rollup-plugin-node-externals": "^8.1.2",
|
||||
"vite": "^7.2.2",
|
||||
"vite": "^7.2.4",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue