diff --git a/src/tic-tac-toe/package.json b/src/tic-tac-toe/package.json index 503c4fc..3f85226 100644 --- a/src/tic-tac-toe/package.json +++ b/src/tic-tac-toe/package.json @@ -15,7 +15,21 @@ "license": "ISC", "packageManager": "pnpm@10.24.0", "dependencies": { - "fastify-socket.io": "^5.1.0", - "socket.io": "^4.8.1" + "@fastify/autoload": "^6.3.1", + "@fastify/formbody": "^8.0.2", + "@fastify/multipart": "^9.3.0", + "@fastify/sensible": "^6.0.4", + "@fastify/static": "^8.3.0", + "@fastify/websocket": "^11.2.0", + "fastify": "^5.6.2", + "fastify-plugin": "^5.1.0", + "socket.io": "^4.8.1", + "typebox": "^1.0.63" + }, + "devDependencies": { + "@types/node": "^22.19.3", + "rollup-plugin-node-externals": "^8.1.2", + "vite": "^7.3.0", + "vite-tsconfig-paths": "^5.1.4" } } diff --git a/src/tic-tac-toe/src/app.ts b/src/tic-tac-toe/src/app.ts index 896d366..7486a9a 100644 --- a/src/tic-tac-toe/src/app.ts +++ b/src/tic-tac-toe/src/app.ts @@ -1,56 +1,101 @@ -import { FastifyInstance, FastifyPluginAsync } from 'fastify'; -import fastifySocketIO from 'fastify-socket.io'; import { TTC } from './game'; +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 { Server } from 'socket.io'; -const app: FastifyPluginAsync = async (fastify: FastifyInstance, opts): Promise => { +declare const __SERVICE_NAME: string; + +// @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... +const routes = import.meta.glob('./routes/**/*.ts', { eager: true }); + +const app: FastifyPluginAsync = async (fastify, opts): Promise => { void opts; - await fastify.register(fastifySocketIO, { - cors: { - origin: '*', - methods: ['GET', 'POST'], - }, - }); + + 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, {}); + await fastify.register(auth.jwtPlugin as FastifyPluginAsync, {}); + await fastify.register(auth.authPlugin as FastifyPluginAsync, {}); + + // Place here your custom code! + for (const plugin of Object.values(plugins)) { + void fastify.register(plugin as FastifyPluginAsync, {}); + } + for (const route of Object.values(routes)) { + void fastify.register(route as FastifyPluginAsync, {}); + } + + void fastify.register(fastifyFormBody, {}); + void fastify.register(fastifyMultipart, {}); const game = new TTC(); - fastify.ready().then(() => { - fastify.io.on('connection', (socket) => { - fastify.log.info(`Client connected: ${socket.id}`); + fastify.ready((err) => { + if (err) throw err; + onReady(fastify, game); + }); +}; +export default app; +export { app }; - socket.emit('gameState', { - board: game.board, - turn: game.currentPlayer, - gameOver: game.isGameOver, - }); +// When using .decorate you have to specify added properties for Typescript +declare module 'fastify' { + interface FastifyInstance { + io: Server<{ + hello: (message: string) => string; + // idk you put something + // eslint-disable-next-line @typescript-eslint/no-explicit-any + gameState: any; + makeMove: (idx: number) => void; + resetGame: () => void; + error: string, + }>; + } +} - socket.on('makeMove', (idx: number) => { - const result = game.makeMove(idx); +async function onReady(fastify: FastifyInstance, game: TTC) { + fastify.io.on('connection', (socket) => { + fastify.log.info(`Client connected: ${socket.id}`); - if (result === 'invalidMove') { - socket.emit('error', 'Invalid Move'); - } - else { - fastify.io.emit('gameState', { - board: game.board, - turn: game.currentPlayer, - lastResult: result, - }); - } - }); + socket.emit('gameState', { + board: game.board, + turn: game.currentPlayer, + gameOver: game.isGameOver, + }); - socket.on('resetGame', () => { - game.reset(); + socket.on('makeMove', (idx: number) => { + const result = game.makeMove(idx); + + if (result === 'invalidMove') { + socket.emit('error', 'Invalid Move'); + } + else { fastify.io.emit('gameState', { board: game.board, turn: game.currentPlayer, - reset: true, + lastResult: result, }); + } + }); + + socket.on('resetGame', () => { + game.reset(); + fastify.io.emit('gameState', { + board: game.board, + turn: game.currentPlayer, + reset: true, }); }); }); -}; - -export default app; +} // // TODO: Import the plugins defined for this microservice // // TODO: Import the routes defined for this microservice @@ -237,4 +282,5 @@ export default app; // // } // // }); // // }); -// // } \ No newline at end of file +// // } + diff --git a/src/tic-tac-toe/src/game.ts b/src/tic-tac-toe/src/game.ts index a08a2e4..c472e50 100644 --- a/src/tic-tac-toe/src/game.ts +++ b/src/tic-tac-toe/src/game.ts @@ -78,4 +78,4 @@ export class TTC { return result; } -} \ No newline at end of file +} diff --git a/src/tic-tac-toe/src/plugins/.gitkeep b/src/tic-tac-toe/src/plugins/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/tic-tac-toe/src/plugins/socket.ts b/src/tic-tac-toe/src/plugins/socket.ts new file mode 100644 index 0000000..f32dec8 --- /dev/null +++ b/src/tic-tac-toe/src/plugins/socket.ts @@ -0,0 +1,31 @@ +import type { + FastifyInstance, + FastifyPluginAsync, + HookHandlerDoneFunction, +} from 'fastify'; +import fp from 'fastify-plugin'; +import { Server } from 'socket.io'; + +const F: ( + f: FastifyInstance, +) => Omit & { io: Server } = (f) => + f as Omit & { 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(); + }); +}); + +export default fastifySocketIO; + diff --git a/src/tic-tac-toe/src/routes/.gitkeep b/src/tic-tac-toe/src/routes/.gitkeep new file mode 100644 index 0000000..e69de29