From 1cb3f49ac02b310ae66e8125c39728c11877b5d3 Mon Sep 17 00:00:00 2001 From: hhow09 Date: Wed, 22 Jan 2025 17:51:53 +0100 Subject: [PATCH] feat: read command and response - use repository in app - test with simple html --- backend/src/app.ts | 19 ++++- backend/src/chat-server.ts | 29 +++++++- backend/src/command-service.ts | 7 +- backend/src/repositories/chat-repo.spec.ts | 5 +- backend/src/repositories/chat-repo.ts | 2 +- frontend/test_index.html | 86 +++++++++++++--------- 6 files changed, 109 insertions(+), 39 deletions(-) diff --git a/backend/src/app.ts b/backend/src/app.ts index 643bba9..fa34e91 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -1,6 +1,23 @@ import pino from "pino"; import { ChatServer } from "./chat-server"; +import CommandService from "./command-service"; +import ChatRepo, { ChatSession } from "./repositories/chat-repo"; +import { MongoClient, Collection } from "mongodb"; + +// config, consider to use env variables in the future +const uri = process.env.MONGODB_URI || "mongodb://localhost:27017"; +const dbName = "math-chat"; +const collectionName = "chat-session"; const logger = pino(); -const chatServer = new ChatServer(logger, 3000); +const collection = getMongoCollection(uri, dbName, collectionName); +const commandService = new CommandService(logger, new ChatRepo(collection)); +const chatServer = new ChatServer(logger, commandService, 3000); chatServer.listen(); + +function getMongoCollection(uri: string, dbName: string, collectionName: string): Collection { + const mongoClient = new MongoClient(uri); + const db = mongoClient.db(dbName); + const collection = db.collection(collectionName); + return collection; +} \ No newline at end of file diff --git a/backend/src/chat-server.ts b/backend/src/chat-server.ts index 4909c63..ee74c13 100644 --- a/backend/src/chat-server.ts +++ b/backend/src/chat-server.ts @@ -1,17 +1,20 @@ import express, { Request, Response } from 'express'; import { Logger } from "pino"; import { Server, Socket } from "socket.io"; +import { ICommandService } from './command-service'; export class ChatServer { port: number; app: express.Application; logger: Logger; + commandService: ICommandService; - constructor(logger: Logger, port: number = 3000) { + constructor(logger: Logger, commandService: ICommandService, port: number = 3000) { this.port = port; this.logger = logger; this.app = express(); this.setupAppRoutes(); + this.commandService = commandService; } private setupAppRoutes() { // health check @@ -25,12 +28,36 @@ export class ChatServer { io.on('connection', (socket: Socket) => { const sessionLogger = this.logger.child({ session: socket.id }); sessionLogger.info(`Connected client session ${socket.id} on port ${this.port}`); + socket.on('operation', async (operation: string) => { + sessionLogger.info(`Received operation: ${operation}`); + try { + const result = await this.commandService.evaluateAndSave(socket.id, operation); + sessionLogger.info(`Returning result: ${result}`); + socket.emit('result', result); + } catch (error) { + this.handleSocketError(socket, sessionLogger, "operation", error as Error); + } + }); + socket.on('history', async () => { + try { + const history = await this.commandService.getHistory(socket.id); + sessionLogger.info(`Returning history: ${JSON.stringify(history)}`); + socket.emit('history', history); + } catch (error) { + this.handleSocketError(socket, sessionLogger, "history", error as Error); + } + }); socket.on('disconnect', () => { sessionLogger.info('a client disconnected'); }); }); } + private handleSocketError(socket: Socket, logger: Logger, operation: string, error: Error) { + logger.error(`Error during operation: ${operation}`, error); + socket.emit('error', error instanceof Error ? error.message : String(error)); + } + public listen() { const httpServer = this.app.listen(this.port, () => { console.log(`Server listening on port ${this.port}`) } diff --git a/backend/src/command-service.ts b/backend/src/command-service.ts index d083c0a..cdf0bde 100644 --- a/backend/src/command-service.ts +++ b/backend/src/command-service.ts @@ -3,7 +3,12 @@ import { evaluate as evaluateMathjs } from 'mathjs'; import { CommandAndResult } from "./entities/command-result.entity"; import { IRepository } from "./repositories"; -class CommandService { +export interface ICommandService { + evaluateAndSave(clientId: string, expression: string): Promise; + getHistory(clientId: string): Promise; +} + +class CommandService implements ICommandService { private operators = new Set(['+', '-', '*', '/']); private repository: IRepository; private logger: Logger; diff --git a/backend/src/repositories/chat-repo.spec.ts b/backend/src/repositories/chat-repo.spec.ts index 306634f..3a21a74 100644 --- a/backend/src/repositories/chat-repo.spec.ts +++ b/backend/src/repositories/chat-repo.spec.ts @@ -39,8 +39,9 @@ describe("ChatRepo", () => { expect(history2).toEqual([expected[1]]); }); - it("should throw an error if the chat session is not found", async () => { - await expect(repo.getLatest(clientId)).rejects.toThrow("Chat session not found"); + it("should return an empty array if the chat session is not found", async () => { + const history = await repo.getLatest(clientId); + expect(history).toEqual([]); }); diff --git a/backend/src/repositories/chat-repo.ts b/backend/src/repositories/chat-repo.ts index 0f840a6..26a13ce 100644 --- a/backend/src/repositories/chat-repo.ts +++ b/backend/src/repositories/chat-repo.ts @@ -46,7 +46,7 @@ class ChatRepo implements IRepository { public async getLatest(clientId: string): Promise { const chatSession = await this.db_client.findOne({ clientId }); if (!chatSession) { - throw new Error("Chat session not found"); + return []; } return chatSession.history; } diff --git a/frontend/test_index.html b/frontend/test_index.html index 115165c..31f1991 100644 --- a/frontend/test_index.html +++ b/frontend/test_index.html @@ -1,46 +1,66 @@ - - - - Socket.IO Fiddle - - - -

Status: Disconnected

-

Messages:

+ + + + Simple Chat + +
    - +
    + + +
    + +
      + - - - \ No newline at end of file + +