From f2057e96f8ece2abe95e6c18f06230f61c424d20 Mon Sep 17 00:00:00 2001 From: dm1sh Date: Sat, 4 Sep 2021 16:46:50 +0300 Subject: [PATCH] Refactored messaging system. Now messages about room state sent from user and server are same. Added "broadcasting" of room state update --- back/src/db/model.ts | 16 ++++++++-------- back/src/index.ts | 31 ++++++++++++++++++++++--------- back/src/types.ts | 23 ++++++++++++----------- back/tsconfig.json | 2 +- 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/back/src/db/model.ts b/back/src/db/model.ts index 1ee0c9a..bc8ecf1 100644 --- a/back/src/db/model.ts +++ b/back/src/db/model.ts @@ -1,27 +1,27 @@ import { Entity, Column, PrimaryGeneratedColumn } from "typeorm"; @Entity() -export class Room { +export abstract class Room { @PrimaryGeneratedColumn() - id: number; + abstract id: number; @Column({ length: 100, }) - title: string; + abstract title: string; @Column() - free: boolean; + abstract free: boolean; @Column() - x: number; + abstract x: number; @Column() - y: number; + abstract y: number; @Column() - width: number; + abstract width: number; @Column() - height: number; + abstract height: number; } diff --git a/back/src/index.ts b/back/src/index.ts index 5f56f33..ae85e6c 100644 --- a/back/src/index.ts +++ b/back/src/index.ts @@ -1,9 +1,9 @@ import "reflect-metadata"; -import { Server } from "ws"; +import { Server, OPEN } from "ws"; import { connect, getRoomList, updateFree } from "./db"; -import { isIdMessage, isMessage } from "./types"; +import { isMessage, isUpdateMessage } from "./types"; -(async () => { +const main = async () => { const connection = await connect(); const wss = new Server({ @@ -13,12 +13,25 @@ import { isIdMessage, isMessage } from "./types"; wss.on("connection", async (ws) => { ws.send(JSON.stringify(await getRoomList(connection))); - ws.on("message", (data) => { - const message: unknown = JSON.parse(data.toString()); - if (!isMessage(message)) throw new Error("Message corrupted"); + ws.on("message", async (data) => { + try { + const message: unknown = JSON.parse(data.toString()); + if (!isMessage(message)) throw new Error("Message corrupted"); - if (isIdMessage(message)) - updateFree(connection, message.args.id, message.type === "freed"); + if (isUpdateMessage(message)) { + const { id, value } = message.args; + await updateFree(connection, id, value); + + wss.clients.forEach((client) => { + if (client.readyState === OPEN) + client.send(JSON.stringify(message)); + }); + } + } catch (err) { + console.log("Error processing message", err); + } }); }); -})(); +}; + +main(); diff --git a/back/src/types.ts b/back/src/types.ts index 78acf14..3c76f1c 100644 --- a/back/src/types.ts +++ b/back/src/types.ts @@ -1,32 +1,33 @@ -import { idMsgTypes } from "./constants"; - -export type IdMsgTypes = typeof idMsgTypes[number]; - export type Message = { type: string; args: unknown; }; -export type IdMessage = Message & { - type: IdMsgTypes; +export type UpdateMessage = Message & { + type: "update"; args: { id: number; + value: boolean; }; }; +const isObjLike = (obj: unknown): obj is object => + Boolean(obj) && typeof obj === "object"; + const hasProperty = ( obj: T, prop: U ): obj is T & Record => prop in obj; export const isMessage = (obj: unknown): obj is Message => - typeof obj === "object" && + isObjLike(obj) && hasProperty(obj, "type") && typeof obj.type === "string" && hasProperty(obj, "args"); -export const isIdMessage = (message: Message): message is IdMessage => - idMsgTypes.reduce((prev, curr) => prev || curr === message.type, false) && - typeof message.args === "object" && +export const isUpdateMessage = (message: Message): message is UpdateMessage => + isObjLike(message.args) && hasProperty(message.args, "id") && - typeof message.args.id === "number"; + typeof message.args.id === "number" && + hasProperty(message.args, "value") && + typeof message.args.value === "boolean"; diff --git a/back/tsconfig.json b/back/tsconfig.json index 7d1d347..8447763 100644 --- a/back/tsconfig.json +++ b/back/tsconfig.json @@ -5,7 +5,7 @@ "esModuleInterop": true, "moduleResolution": "node", "forceConsistentCasingInFileNames": true, - "strict": false, + "strict": true, "skipLibCheck": true, "emitDecoratorMetadata": true, "experimentalDecorators": true,