From e1a6f650fb5e7181c955cec2c64276fdf4e4af9f Mon Sep 17 00:00:00 2001 From: Dennis Postma Date: Sat, 28 Dec 2024 20:40:05 +0100 Subject: [PATCH] Continuation of refactor --- src/application/base/baseCommand.ts | 3 + src/application/base/baseController.ts | 4 +- src/application/base/baseEntity.ts | 4 +- src/application/base/baseEvent.ts | 4 +- src/application/base/baseRepository.ts | 4 +- src/application/base/baseService.ts | 4 +- src/application/database.ts | 7 +- src/application/logger.ts | 110 +++++++----------- src/http/controllers/auth.ts | 15 +-- src/managers/commandManager.ts | 17 +-- src/managers/dateManager.ts | 11 +- src/managers/queueManager.ts | 21 ++-- src/managers/userManager.ts | 5 +- src/managers/zoneManager.ts | 9 +- src/server.ts | 5 +- src/socketEvents/character/create.ts | 15 +-- .../chat/gameMaster/alertCommand.ts | 24 ++-- .../chat/gameMaster/setTimeCommand.ts | 24 ++-- .../chat/gameMaster/teleportCommand.ts | 26 ++--- .../chat/gameMaster/toggleFogCommand.ts | 22 ++-- .../chat/gameMaster/toggleRainCommand.ts | 22 ++-- src/socketEvents/chat/message.ts | 26 ++--- src/socketEvents/disconnect.ts | 2 +- src/socketEvents/login.ts | 2 +- src/socketEvents/zone/characterLeave.ts | 2 +- src/socketEvents/zone/characterMove.ts | 4 +- src/socketEvents/zone/weather.ts | 2 +- 27 files changed, 158 insertions(+), 236 deletions(-) diff --git a/src/application/base/baseCommand.ts b/src/application/base/baseCommand.ts index 2ef9dfa..9a688c0 100644 --- a/src/application/base/baseCommand.ts +++ b/src/application/base/baseCommand.ts @@ -1,5 +1,8 @@ import { Server } from 'socket.io' +import Logger, { LoggerType } from '#application/logger' + export abstract class BaseCommand { + protected readonly logger = Logger.type(LoggerType.COMMAND) constructor(readonly io: Server) {} } diff --git a/src/application/base/baseController.ts b/src/application/base/baseController.ts index addb62e..f222148 100644 --- a/src/application/base/baseController.ts +++ b/src/application/base/baseController.ts @@ -1,9 +1,9 @@ import { Request, Response } from 'express' -import { Logger } from '#application/logger' +import Logger, { LoggerType } from '#application/logger' export abstract class BaseController { - protected readonly logger: Logger = new Logger('http') + protected readonly logger = Logger.type(LoggerType.HTTP) protected sendSuccess(res: Response, data?: any, message?: string, status: number = 200) { return res.status(status).json({ diff --git a/src/application/base/baseEntity.ts b/src/application/base/baseEntity.ts index cd65480..a1d1817 100644 --- a/src/application/base/baseEntity.ts +++ b/src/application/base/baseEntity.ts @@ -1,10 +1,10 @@ import { EntityManager } from '@mikro-orm/core' import Database from '#application/database' -import { Logger } from '#application/logger' +import Logger, { LoggerType } from '#application/logger' export abstract class BaseEntity { - protected readonly logger: Logger = new Logger('entity') + protected readonly logger = Logger.type(LoggerType.ENTITY) private getEntityManager(): EntityManager { return Database.getEntityManager() diff --git a/src/application/base/baseEvent.ts b/src/application/base/baseEvent.ts index b9b84bd..c4b0622 100644 --- a/src/application/base/baseEvent.ts +++ b/src/application/base/baseEvent.ts @@ -1,10 +1,10 @@ import { Server } from 'socket.io' -import { Logger } from '#application/logger' +import Logger, { LoggerType } from '#application/logger' import { TSocket } from '#application/types' export abstract class BaseEvent { - protected readonly logger: Logger = new Logger('game') + protected readonly logger = Logger.type(LoggerType.GAME) constructor( readonly io: Server, diff --git a/src/application/base/baseRepository.ts b/src/application/base/baseRepository.ts index 646aee4..ca89c54 100644 --- a/src/application/base/baseRepository.ts +++ b/src/application/base/baseRepository.ts @@ -2,10 +2,10 @@ import { EntityManager } from '@mikro-orm/core' import Database from '../database' -import { Logger } from '#application/logger' +import Logger, { LoggerType } from '#application/logger' export abstract class BaseRepository { - protected readonly logger: Logger = new Logger('repository') + protected readonly logger = Logger.type(LoggerType.REPOSITORY) protected get em(): EntityManager { return Database.getEntityManager() diff --git a/src/application/base/baseService.ts b/src/application/base/baseService.ts index 73def07..3d80581 100644 --- a/src/application/base/baseService.ts +++ b/src/application/base/baseService.ts @@ -1,5 +1,5 @@ -import { Logger } from '#application/logger' +import Logger, { LoggerType } from '#application/logger' export abstract class BaseService { - protected readonly logger: Logger = new Logger('game') + protected readonly logger = Logger.type(LoggerType.GAME) } diff --git a/src/application/database.ts b/src/application/database.ts index bd54213..77994c2 100644 --- a/src/application/database.ts +++ b/src/application/database.ts @@ -1,20 +1,21 @@ import { EntityManager } from '@mikro-orm/core' import { MikroORM } from '@mikro-orm/mysql' -import { appLogger } from './logger' +import Logger, { LoggerType } from './logger' import config from '../../mikro-orm.config' class Database { private static orm: MikroORM private static em: EntityManager + private static logger = Logger.type(LoggerType.APP) public static async initialize(): Promise { try { Database.orm = await MikroORM.init(config) Database.em = Database.orm.em.fork() - appLogger.info('Database connection initialized') + this.logger.info('Database connection initialized') } catch (error) { - appLogger.error(`MikroORM connection failed: ${error}`) + this.logger.error(`MikroORM connection failed: ${error}`) throw error } } diff --git a/src/application/logger.ts b/src/application/logger.ts index f04a3e0..2202d5c 100644 --- a/src/application/logger.ts +++ b/src/application/logger.ts @@ -1,73 +1,51 @@ import pino from 'pino' -import { getRootPath } from './storage' +export enum LoggerType { + HTTP = 'http', + GAME = 'game', + GAME_MASTER = 'gameMaster', + APP = 'app', + QUEUE = 'queue', + COMMAND = 'command', + REPOSITORY = 'repository', + ENTITY = 'entity' +} -export class Logger { - private static readonly LOG_TYPES = ['http', 'game', 'gameMaster', 'app', 'queue', 'command', 'repository', 'entity'] as const - private readonly logger: ReturnType +class Logger { + private instances: Map> = new Map() - constructor(type: (typeof Logger.LOG_TYPES)[number]) { - this.logger = pino({ - level: process.env.LOG_LEVEL || 'debug', - transport: { - target: 'pino/file', - options: { - destination: `./logs/${type}.log`, - mkdir: true - } - }, - formatters: { - level: (label) => ({ level: label.toUpperCase() }) - }, - timestamp: pino.stdTimeFunctions.isoTime, - base: null - }) - } - - info(message: string) { - this.logger.info(message) - } - - error(message: string) { - this.logger.error(message) - } - - warn(message: string) { - this.logger.warn(message) - } - - debug(message: string) { - this.logger.debug(message) - } - - static watch() { - const fs = require('fs') - - this.LOG_TYPES.forEach((type) => { - const logFile = getRootPath('logs', `${type}.log`) - const stats = fs.statSync(logFile) - let lastPosition = stats.size - - fs.watch(logFile, (eventType: string) => { - if (eventType !== 'change') return - - fs.stat(logFile, (err: Error, stats: { size: number }) => { - if (err) return - - if (stats.size > lastPosition) { - const stream = fs.createReadStream(logFile, { - start: lastPosition, - end: stats.size - }) - - stream.on('data', (chunk: Buffer) => { - console.log(`[${type}]\n${chunk.toString()}`) - }) - - lastPosition = stats.size - } + private getLogger(type: LoggerType): ReturnType { + if (!this.instances.has(type)) { + this.instances.set( + type, + pino({ + level: process.env.LOG_LEVEL || 'debug', + transport: { + target: 'pino/file', + options: { + destination: `./logs/${type}.log`, + mkdir: true + } + }, + formatters: { + level: (label) => ({ level: label.toUpperCase() }) + }, + timestamp: pino.stdTimeFunctions.isoTime, + base: null }) - }) - }) + ) + } + return this.instances.get(type)! + } + + type(type: LoggerType) { + return { + info: (message: string, ...args: any[]) => this.getLogger(type).info(message, ...args), + error: (message: string, ...args: any[]) => this.getLogger(type).error(message, ...args), + warn: (message: string, ...args: any[]) => this.getLogger(type).warn(message, ...args), + debug: (message: string, ...args: any[]) => this.getLogger(type).debug(message, ...args) + } } } + +export default new Logger() diff --git a/src/http/controllers/auth.ts b/src/http/controllers/auth.ts index 7ce99db..21fc2bc 100644 --- a/src/http/controllers/auth.ts +++ b/src/http/controllers/auth.ts @@ -7,13 +7,6 @@ import { loginAccountSchema, registerAccountSchema, resetPasswordSchema, newPass import UserService from '#services/userService' export class AuthController extends BaseController { - private userService: UserService - - constructor() { - super() - this.userService = new UserService() - } - /** * Login user * @param req @@ -24,7 +17,7 @@ export class AuthController extends BaseController { try { loginAccountSchema.parse({ username, password }) - const user = await this.userService.login(username, password) + const user = await UserService.login(username, password) if (user && typeof user !== 'boolean') { const token = jwt.sign({ id: user.getId() }, config.JWT_SECRET, { expiresIn: '4h' }) @@ -47,7 +40,7 @@ export class AuthController extends BaseController { try { registerAccountSchema.parse({ username, email, password }) - const user = await this.userService.register(username, email, password) + const user = await UserService.register(username, email, password) if (user) { return this.sendSuccess(res, null, 'User registered successfully') @@ -69,7 +62,7 @@ export class AuthController extends BaseController { try { resetPasswordSchema.parse({ email }) - const sentEmail = await this.userService.requestPasswordReset(email) + const sentEmail = await UserService.requestPasswordReset(email) if (sentEmail) { return this.sendSuccess(res, null, 'Password reset email sent') @@ -91,7 +84,7 @@ export class AuthController extends BaseController { try { newPasswordSchema.parse({ urlToken, password }) - const resetPassword = await this.userService.resetPassword(urlToken, password) + const resetPassword = await UserService.resetPassword(urlToken, password) if (resetPassword) { return this.sendSuccess(res, null, 'Password has been reset') diff --git a/src/managers/commandManager.ts b/src/managers/commandManager.ts index c89f7c0..4119935 100644 --- a/src/managers/commandManager.ts +++ b/src/managers/commandManager.ts @@ -4,10 +4,11 @@ import * as readline from 'readline' import { Server } from 'socket.io' -import { commandLogger } from '#application/logger' +import Logger, { LoggerType } from '#application/logger' import { getAppPath } from '#application/storage' class CommandManager { + private logger = Logger.type(LoggerType.COMMAND) private commands: Map = new Map() private rl: readline.Interface private io: Server | null = null @@ -27,7 +28,7 @@ class CommandManager { public async boot(io: Server) { this.io = io await this.loadCommands() - commandLogger.info('Command manager loaded') + this.logger.info('Command manager loaded') this.startPrompt() } @@ -64,7 +65,7 @@ class CommandManager { private async loadCommands() { const directory = getAppPath('commands') - commandLogger.info(`Loading commands from: ${directory}`) + this.logger.info(`Loading commands from: ${directory}`) try { const files = await fs.promises.readdir(directory, { withFileTypes: true }) @@ -80,26 +81,26 @@ class CommandManager { try { const module = await import(fullPath) if (typeof module.default !== 'function') { - commandLogger.warn(`Unrecognized export in ${file.name}`) + this.logger.warn(`Unrecognized export in ${file.name}`) continue } this.registerCommand(commandName, module.default) } catch (error) { - commandLogger.error(`Error loading command ${file.name}: ${error instanceof Error ? error.message : String(error)}`) + this.logger.error(`Error loading command ${file.name}: ${error instanceof Error ? error.message : String(error)}`) } } } catch (error) { - commandLogger.error(`Failed to read commands directory: ${error instanceof Error ? error.message : String(error)}`) + this.logger.error(`Failed to read commands directory: ${error instanceof Error ? error.message : String(error)}`) } } private registerCommand(name: string, CommandClass: any) { if (this.commands.has(name)) { - commandLogger.warn(`Command '${name}' is already registered. Overwriting...`) + this.logger.warn(`Command '${name}' is already registered. Overwriting...`) } this.commands.set(name, CommandClass) - commandLogger.info(`Registered command: ${name}`) + this.logger.info(`Registered command: ${name}`) } } diff --git a/src/managers/dateManager.ts b/src/managers/dateManager.ts index 4a1248c..3a554e8 100644 --- a/src/managers/dateManager.ts +++ b/src/managers/dateManager.ts @@ -1,6 +1,6 @@ import { Server } from 'socket.io' -import { appLogger } from '#application/logger' +import Logger, { LoggerType } from '#application/logger' import worldRepository from '#repositories/worldRepository' import worldService from '#services/worldService' @@ -11,12 +11,13 @@ class DateManager { private io: Server | null = null private intervalId: NodeJS.Timeout | null = null private currentDate: Date = new Date() + private logger = Logger.type(LoggerType.APP) public async boot(io: Server): Promise { this.io = io await this.loadDate() this.startDateLoop() - appLogger.info('Date manager loaded') + this.logger.info('Date manager loaded') } public async setTime(time: string): Promise { @@ -38,7 +39,7 @@ class DateManager { this.emitDate() await this.saveDate() } catch (error) { - appLogger.error(`Failed to set time: ${error instanceof Error ? error.message : String(error)}`) + this.logger.error(`Failed to set time: ${error instanceof Error ? error.message : String(error)}`) throw error } } @@ -51,7 +52,7 @@ class DateManager { this.currentDate = world.date } } catch (error) { - appLogger.error(`Failed to load date: ${error instanceof Error ? error.message : String(error)}`) + this.logger.error(`Failed to load date: ${error instanceof Error ? error.message : String(error)}`) this.currentDate = new Date() // Use current date as fallback } } @@ -82,7 +83,7 @@ class DateManager { date: this.currentDate }) } catch (error) { - appLogger.error(`Failed to save date: ${error instanceof Error ? error.message : String(error)}`) + this.logger.error(`Failed to save date: ${error instanceof Error ? error.message : String(error)}`) } } diff --git a/src/managers/queueManager.ts b/src/managers/queueManager.ts index 6d79948..51dde32 100644 --- a/src/managers/queueManager.ts +++ b/src/managers/queueManager.ts @@ -5,7 +5,7 @@ import IORedis from 'ioredis' import { Server as SocketServer } from 'socket.io' import config from '#application/config' -import { queueLogger } from '#application/logger' +import Logger, { LoggerType } from '#application/logger' import { getAppPath } from '#application/storage' import { TSocket } from '#application/types' @@ -14,6 +14,7 @@ class QueueManager { private queue!: Queue private worker!: Worker private io!: SocketServer + private logger = Logger.type(LoggerType.QUEUE) public async boot(io: SocketServer) { this.io = io @@ -24,9 +25,9 @@ class QueueManager { try { await this.connection.ping() - queueLogger.info('Successfully connected to Redis') + this.logger.info('Successfully connected to Redis') } catch (error) { - queueLogger.error('Failed to connect to Redis:', error) + this.logger.error('Failed to connect to Redis:', error) process.exit(1) } @@ -40,14 +41,14 @@ class QueueManager { }) this.worker.on('completed', (job) => { - queueLogger.info(`Job ${job?.id} has completed`) + this.logger.info(`Job ${job?.id} has completed`) }) this.worker.on('failed', (job, err) => { - queueLogger.error(`Job ${job?.id} failed with error: ${err}`) + this.logger.error(`Job ${job?.id} failed with error: ${err}`) }) - queueLogger.info('Queue manager loaded') + this.logger.info('Queue manager loaded') } private async processJob(job: Job) { @@ -59,7 +60,7 @@ class QueueManager { const jobPath = getAppPath('jobs', `${jobName}${extension}`) if (!fs.existsSync(jobPath)) { - queueLogger.warn(`Job file not found: ${jobPath}`) + this.logger.warn(`Job file not found: ${jobPath}`) return } @@ -67,7 +68,7 @@ class QueueManager { const JobClass = JobModule.default if (!JobClass || typeof JobClass !== 'function') { - queueLogger.warn(`Invalid job class in file: ${jobPath}`) + this.logger.warn(`Invalid job class in file: ${jobPath}`) return } @@ -78,14 +79,14 @@ class QueueManager { if (socket) { await jobInstance.execute(this.io, socket) } else { - queueLogger.warn(`Socket not found for job: ${socketId}`) + this.logger.warn(`Socket not found for job: ${socketId}`) await jobInstance.execute(this.io) } } else { await jobInstance.execute(this.io) } } catch (error: any) { - queueLogger.error(`Error processing job ${jobName}: ${error.message}`) + this.logger.error(`Error processing job ${jobName}: ${error.message}`) } } diff --git a/src/managers/userManager.ts b/src/managers/userManager.ts index 992819f..d670a27 100644 --- a/src/managers/userManager.ts +++ b/src/managers/userManager.ts @@ -1,6 +1,6 @@ import { User } from '@prisma/client' -import { appLogger } from '#application/logger' +import Logger, { LoggerType } from '#application/logger' type TLoggedInUsers = { users: User[] @@ -8,10 +8,11 @@ type TLoggedInUsers = { class UserManager { private loggedInUsers: TLoggedInUsers[] = [] + private logger = Logger.type(LoggerType.APP) // Method to initialize user manager public async boot() { - appLogger.info('User manager loaded') + this.logger.info('User manager loaded') } // Function that adds user to logged in users diff --git a/src/managers/zoneManager.ts b/src/managers/zoneManager.ts index a1e3a67..dc39232 100644 --- a/src/managers/zoneManager.ts +++ b/src/managers/zoneManager.ts @@ -1,4 +1,4 @@ -import { gameLogger } from '#application/logger' +import Logger, { LoggerType } from '#application/logger' import { Zone } from '#entities/zone' import LoadedZone from '#models/loadedZone' import ZoneCharacter from '#models/zoneCharacter' @@ -6,23 +6,24 @@ import ZoneRepository from '#repositories/zoneRepository' class ZoneManager { private readonly zones = new Map() + private logger = Logger.type(LoggerType.GAME) public async boot(): Promise { const zones = await ZoneRepository.getAll() await Promise.all(zones.map((zone) => this.loadZone(zone))) - gameLogger.info(`Zone manager loaded with ${this.zones.size} zones`) + this.logger.info(`Zone manager loaded with ${this.zones.size} zones`) } public async loadZone(zone: Zone): Promise { const loadedZone = new LoadedZone(zone) this.zones.set(zone.id, loadedZone) - gameLogger.info(`Zone ID ${zone.id} loaded`) + this.logger.info(`Zone ID ${zone.id} loaded`) } public unloadZone(zoneId: number): void { this.zones.delete(zoneId) - gameLogger.info(`Zone ID ${zoneId} unloaded`) + this.logger.info(`Zone ID ${zoneId} unloaded`) } public getLoadedZones(): LoadedZone[] { diff --git a/src/server.ts b/src/server.ts index 6f86590..52fe6a0 100644 --- a/src/server.ts +++ b/src/server.ts @@ -7,7 +7,7 @@ import { Server as SocketServer } from 'socket.io' import config from '#application/config' import Database from '#application/database' -import { Logger } from '#application/logger' +import Logger, { LoggerType } from '#application/logger' import { getAppPath } from '#application/storage' import { TSocket } from '#application/types' import { HttpRouter } from '#http/router' @@ -23,7 +23,7 @@ export class Server { private readonly app: Application private readonly http: HTTPServer private readonly io: SocketServer - private readonly logger: Logger = new Logger('app') + private readonly logger = Logger.type(LoggerType.APP) /** * Creates an instance of GameServer. @@ -50,7 +50,6 @@ export class Server { */ public async start() { // Read log file and print to console for debugging - Logger.watch() // Connect to database try { diff --git a/src/socketEvents/character/create.ts b/src/socketEvents/character/create.ts index 81c39fa..b66d6b4 100644 --- a/src/socketEvents/character/create.ts +++ b/src/socketEvents/character/create.ts @@ -1,19 +1,12 @@ -import { Server } from 'socket.io' import { ZodError } from 'zod' -import { gameLogger } from '#application/logger' -import { TSocket } from '#application/types' +import { BaseEvent } from '#application/base/baseEvent' import { ZCharacterCreate } from '#application/zodTypes' import { Character } from '#entities/character' import CharacterRepository from '#repositories/characterRepository' import UserRepository from '#repositories/userRepository' -export default class CharacterCreateEvent { - constructor( - private readonly io: Server, - private readonly socket: TSocket - ) {} - +export default class CharacterCreateEvent extends BaseEvent { public listen(): void { this.socket.on('character:create', this.handleCharacterCreate.bind(this)) } @@ -52,9 +45,9 @@ export default class CharacterCreateEvent { this.socket.emit('character:create:success') this.socket.emit('character:list', characters) - gameLogger.info('character:create success') + this.logger.info('character:create success') } catch (error: any) { - gameLogger.error(`character:create error: ${error.message}`) + this.logger.error(`character:create error: ${error.message}`) if (error instanceof ZodError) { return this.socket.emit('notification', { message: error.issues[0].message }) } diff --git a/src/socketEvents/chat/gameMaster/alertCommand.ts b/src/socketEvents/chat/gameMaster/alertCommand.ts index 624be19..5b922cf 100644 --- a/src/socketEvents/chat/gameMaster/alertCommand.ts +++ b/src/socketEvents/chat/gameMaster/alertCommand.ts @@ -1,44 +1,36 @@ -import { Server } from 'socket.io' - -import { getArgs, isCommand } from '#application/chat' -import { gameLogger } from '#application/logger' -import { TSocket } from '#application/types' +import { BaseEvent } from '#application/base/baseEvent' import CharacterRepository from '#repositories/characterRepository' +import ChatService from '#services/chatService' type TypePayload = { message: string } -export default class AlertCommandEvent { - constructor( - private readonly io: Server, - private readonly socket: TSocket - ) {} - +export default class AlertCommandEvent extends BaseEvent { public listen(): void { this.socket.on('chat:message', this.handleAlertCommand.bind(this)) } private async handleAlertCommand(data: TypePayload, callback: (response: boolean) => void): Promise { try { - if (!isCommand(data.message, 'alert')) { + if (!ChatService.isCommand(data.message, 'alert')) { return } // Check if character exists const character = await CharacterRepository.getByUserAndId(this.socket.userId!, this.socket.characterId!) if (!character) { - gameLogger.error('chat:alert_command error', 'Character not found') + this.logger.error('chat:alert_command error', 'Character not found') return callback(false) } // Check if the user is the GM if (character.role !== 'gm') { - gameLogger.info(`User ${character.id} tried to set time but is not a game master.`) + this.logger.info(`User ${character.id} tried to set time but is not a game master.`) return callback(false) } - const args = getArgs('alert', data.message) + const args = ChatService.getArgs('alert', data.message) if (!args) { return callback(false) @@ -47,7 +39,7 @@ export default class AlertCommandEvent { this.io.emit('notification', { title: 'Message from GM', message: args.join(' ') }) return callback(true) } catch (error: any) { - gameLogger.error('chat:alert_command error', error.message) + this.logger.error('chat:alert_command error', error.message) callback(false) } } diff --git a/src/socketEvents/chat/gameMaster/setTimeCommand.ts b/src/socketEvents/chat/gameMaster/setTimeCommand.ts index 3bb2b81..4991d1c 100644 --- a/src/socketEvents/chat/gameMaster/setTimeCommand.ts +++ b/src/socketEvents/chat/gameMaster/setTimeCommand.ts @@ -1,46 +1,38 @@ -import { Server } from 'socket.io' - -import { getArgs, isCommand } from '#application/chat' -import { gameLogger } from '#application/logger' -import { TSocket } from '#application/types' +import { BaseEvent } from '#application/base/baseEvent' import DateManager from '#managers/dateManager' import CharacterRepository from '#repositories/characterRepository' +import ChatService from '#services/chatService' type TypePayload = { message: string } -export default class SetTimeCommand { - constructor( - private readonly io: Server, - private readonly socket: TSocket - ) {} - +export default class SetTimeCommand extends BaseEvent { public listen(): void { this.socket.on('chat:message', this.handleAlertCommand.bind(this)) } private async handleAlertCommand(data: TypePayload, callback: (response: boolean) => void): Promise { try { - if (!isCommand(data.message, 'time')) { + if (!ChatService.isCommand(data.message, 'time')) { return } // Check if character exists const character = await CharacterRepository.getByUserAndId(this.socket.userId!, this.socket.characterId!) if (!character) { - gameLogger.error('chat:alert_command error', 'Character not found') + this.logger.error('chat:alert_command error', 'Character not found') return } // Check if the user is the GM if (character.role !== 'gm') { - gameLogger.info(`User ${character.id} tried to set time but is not a game master.`) + this.logger.info(`User ${character.id} tried to set time but is not a game master.`) return } // Get arguments - const args = getArgs('time', data.message) + const args = ChatService.getArgs('time', data.message) if (!args) { return @@ -54,7 +46,7 @@ export default class SetTimeCommand { await DateManager.setTime(time) } catch (error: any) { - gameLogger.error('command error', error.message) + this.logger.error('command error', error.message) callback(false) } } diff --git a/src/socketEvents/chat/gameMaster/teleportCommand.ts b/src/socketEvents/chat/gameMaster/teleportCommand.ts index 712ab94..de9cc0a 100644 --- a/src/socketEvents/chat/gameMaster/teleportCommand.ts +++ b/src/socketEvents/chat/gameMaster/teleportCommand.ts @@ -1,23 +1,15 @@ -import { Server } from 'socket.io' - -import { getArgs, isCommand } from '#application/chat' -import { gameLogger, gameMasterLogger } from '#application/logger' -import { TSocket } from '#application/types' +import { BaseEvent } from '#application/base/baseEvent' import ZoneManager from '#managers/zoneManager' import zoneManager from '#managers/zoneManager' import ZoneCharacter from '#models/zoneCharacter' import ZoneRepository from '#repositories/zoneRepository' +import ChatService from '#services/chatService' type TypePayload = { message: string } -export default class TeleportCommandEvent { - constructor( - private readonly io: Server, - private readonly socket: TSocket - ) {} - +export default class TeleportCommandEvent extends BaseEvent { public listen(): void { this.socket.on('chat:message', this.handleTeleportCommand.bind(this)) } @@ -27,7 +19,7 @@ export default class TeleportCommandEvent { // Check if character exists const zoneCharacter = ZoneManager.getCharacterById(this.socket.characterId!) if (!zoneCharacter) { - gameLogger.error('chat:message error', 'Character not found') + this.logger.error('chat:message error', 'Character not found') return } @@ -35,13 +27,13 @@ export default class TeleportCommandEvent { // Check if the user is the GM if (character.role !== 'gm') { - gameLogger.info(`User ${character.id} tried to set time but is not a game master.`) + this.logger.info(`User ${character.id} tried to set time but is not a game master.`) return } - if (!isCommand(data.message, 'teleport')) return + if (!ChatService.isCommand(data.message, 'teleport')) return - const args = getArgs('teleport', data.message) + const args = ChatService.getArgs('teleport', data.message) if (!args || args.length !== 1) { this.socket.emit('notification', { title: 'Server message', message: 'Usage: /teleport ' }) @@ -87,9 +79,9 @@ export default class TeleportCommandEvent { }) this.socket.emit('notification', { title: 'Server message', message: `You have been teleported to ${zone.name}` }) - gameMasterLogger.info('teleport', `Character ${character.id} teleported to zone ${zone.id}`) + this.logger.info('teleport', `Character ${character.id} teleported to zone ${zone.id}`) } catch (error: any) { - gameMasterLogger.error(`Error in teleport command: ${error.message}`) + this.logger.error(`Error in teleport command: ${error.message}`) this.socket.emit('notification', { title: 'Server message', message: 'An error occurred while teleporting' }) } } diff --git a/src/socketEvents/chat/gameMaster/toggleFogCommand.ts b/src/socketEvents/chat/gameMaster/toggleFogCommand.ts index f0862d6..9aa215c 100644 --- a/src/socketEvents/chat/gameMaster/toggleFogCommand.ts +++ b/src/socketEvents/chat/gameMaster/toggleFogCommand.ts @@ -1,47 +1,39 @@ -import { Server } from 'socket.io' - -import { isCommand } from '#application/chat' -import { gameLogger } from '#application/logger' -import { TSocket } from '#application/types' +import { BaseEvent } from '#application/base/baseEvent' import WeatherManager from '#managers/weatherManager' import CharacterRepository from '#repositories/characterRepository' +import ChatService from '#services/chatService' type TypePayload = { message: string } -export default class ToggleFogCommand { - constructor( - private readonly io: Server, - private readonly socket: TSocket - ) {} - +export default class ToggleFogCommand extends BaseEvent { public listen(): void { this.socket.on('chat:message', this.handleAlertCommand.bind(this)) } private async handleAlertCommand(data: TypePayload, callback: (response: boolean) => void): Promise { try { - if (!isCommand(data.message, 'fog')) { + if (!ChatService.isCommand(data.message, 'fog')) { return } // Check if character exists const character = await CharacterRepository.getByUserAndId(this.socket.userId!, this.socket.characterId!) if (!character) { - gameLogger.error('chat:alert_command error', 'Character not found') + this.logger.error('chat:alert_command error', 'Character not found') return } // Check if the user is the GM if (character.role !== 'gm') { - gameLogger.info(`User ${character.id} tried to set time but is not a game master.`) + this.logger.info(`User ${character.id} tried to set time but is not a game master.`) return } await WeatherManager.toggleFog() } catch (error: any) { - gameLogger.error('command error', error.message) + this.logger.error('command error', error.message) callback(false) } } diff --git a/src/socketEvents/chat/gameMaster/toggleRainCommand.ts b/src/socketEvents/chat/gameMaster/toggleRainCommand.ts index f0f6930..d451a97 100644 --- a/src/socketEvents/chat/gameMaster/toggleRainCommand.ts +++ b/src/socketEvents/chat/gameMaster/toggleRainCommand.ts @@ -1,47 +1,39 @@ -import { Server } from 'socket.io' - -import { isCommand } from '#application/chat' -import { gameLogger } from '#application/logger' -import { TSocket } from '#application/types' +import { BaseEvent } from '#application/base/baseEvent' import WeatherManager from '#managers/weatherManager' import CharacterRepository from '#repositories/characterRepository' +import ChatService from '#services/chatService' type TypePayload = { message: string } -export default class ToggleRainCommand { - constructor( - private readonly io: Server, - private readonly socket: TSocket - ) {} - +export default class ToggleRainCommand extends BaseEvent { public listen(): void { this.socket.on('chat:message', this.handleAlertCommand.bind(this)) } private async handleAlertCommand(data: TypePayload, callback: (response: boolean) => void): Promise { try { - if (!isCommand(data.message, 'rain')) { + if (!ChatService.isCommand(data.message, 'rain')) { return } // Check if character exists const character = await CharacterRepository.getByUserAndId(this.socket.userId!, this.socket.characterId!) if (!character) { - gameLogger.error('chat:alert_command error', 'Character not found') + this.logger.error('chat:alert_command error', 'Character not found') return } // Check if the user is the GM if (character.role !== 'gm') { - gameLogger.info(`User ${character.id} tried to set time but is not a game master.`) + this.logger.info(`User ${character.id} tried to set time but is not a game master.`) return } await WeatherManager.toggleRain() } catch (error: any) { - gameLogger.error('command error', error.message) + this.logger.error('command error', error.message) callback(false) } } diff --git a/src/socketEvents/chat/message.ts b/src/socketEvents/chat/message.ts index 37a44ba..9ec407a 100644 --- a/src/socketEvents/chat/message.ts +++ b/src/socketEvents/chat/message.ts @@ -1,8 +1,4 @@ -import { Server } from 'socket.io' - -import { isCommand } from '#application/chat' -import { gameLogger } from '#application/logger' -import { TSocket } from '#application/types' +import { BaseEvent } from '#application/base/baseEvent' import ZoneManager from '#managers/zoneManager' import ZoneRepository from '#repositories/zoneRepository' import ChatService from '#services/chatService' @@ -11,44 +7,38 @@ type TypePayload = { message: string } -export default class ChatMessageEvent { - constructor( - private readonly io: Server, - private readonly socket: TSocket - ) {} - +export default class ChatMessageEvent extends BaseEvent { public listen(): void { this.socket.on('chat:message', this.handleEvent.bind(this)) } private async handleEvent(data: TypePayload, callback: (response: boolean) => void): Promise { try { - if (!data.message || isCommand(data.message)) { + if (!data.message || ChatService.isCommand(data.message)) { return callback(false) } const zoneCharacter = ZoneManager.getCharacterById(this.socket.characterId!) if (!zoneCharacter) { - gameLogger.error('chat:message error', 'Character not found') + this.logger.error('chat:message error', 'Character not found') return callback(false) } const character = zoneCharacter.character - const zone = await ZoneRepository.getById(character.zoneId) + const zone = await ZoneRepository.getById(character.zone?.id!) if (!zone) { - gameLogger.error('chat:message error', 'Zone not found') + this.logger.error('chat:message error', 'Zone not found') return callback(false) } - const chatService = new ChatService() - if (await chatService.sendZoneMessage(this.io, this.socket, data.message, character.id, zone.id)) { + if (await ChatService.sendZoneMessage(this.io, this.socket, data.message, character.id, zone.id)) { return callback(true) } callback(false) } catch (error: any) { - gameLogger.error('chat:message error', error.message) + this.logger.error('chat:message error', error.message) callback(false) } } diff --git a/src/socketEvents/disconnect.ts b/src/socketEvents/disconnect.ts index 18eca99..c159361 100644 --- a/src/socketEvents/disconnect.ts +++ b/src/socketEvents/disconnect.ts @@ -1,5 +1,5 @@ -import ZoneManager from '#managers/zoneManager' import { BaseEvent } from '#application/base/baseEvent' +import ZoneManager from '#managers/zoneManager' export default class DisconnectEvent extends BaseEvent { public listen(): void { diff --git a/src/socketEvents/login.ts b/src/socketEvents/login.ts index 85c3d6b..a82179e 100644 --- a/src/socketEvents/login.ts +++ b/src/socketEvents/login.ts @@ -1,5 +1,5 @@ -import UserRepository from '#repositories/userRepository' import { BaseEvent } from '#application/base/baseEvent' +import UserRepository from '#repositories/userRepository' export default class LoginEvent extends BaseEvent { public listen(): void { diff --git a/src/socketEvents/zone/characterLeave.ts b/src/socketEvents/zone/characterLeave.ts index f9eeda4..6b90bdf 100644 --- a/src/socketEvents/zone/characterLeave.ts +++ b/src/socketEvents/zone/characterLeave.ts @@ -1,6 +1,6 @@ +import { BaseEvent } from '#application/base/baseEvent' import ZoneManager from '#managers/zoneManager' import CharacterRepository from '#repositories/characterRepository' -import { BaseEvent } from '#application/base/baseEvent' export default class ZoneLeaveEvent extends BaseEvent { public listen(): void { diff --git a/src/socketEvents/zone/characterMove.ts b/src/socketEvents/zone/characterMove.ts index 005f80c..2a90592 100644 --- a/src/socketEvents/zone/characterMove.ts +++ b/src/socketEvents/zone/characterMove.ts @@ -1,15 +1,15 @@ +import { BaseEvent } from '#application/base/baseEvent' import { ZoneEventTileWithTeleport } from '#application/types' import ZoneManager from '#managers/zoneManager' import ZoneCharacter from '#models/zoneCharacter' import zoneEventTileRepository from '#repositories/zoneEventTileRepository' import CharacterService from '#services/characterService' import ZoneEventTileService from '#services/zoneEventTileService' -import { BaseEvent } from '#application/base/baseEvent' export default class CharacterMove extends BaseEvent { private readonly characterService = CharacterService private readonly zoneEventTileService = ZoneEventTileService - + public listen(): void { this.socket.on('character:move', this.handleEvent.bind(this)) } diff --git a/src/socketEvents/zone/weather.ts b/src/socketEvents/zone/weather.ts index 27f6e1e..5b53d3c 100644 --- a/src/socketEvents/zone/weather.ts +++ b/src/socketEvents/zone/weather.ts @@ -1,5 +1,5 @@ -import WeatherManager from '#managers/weatherManager' import { BaseEvent } from '#application/base/baseEvent' +import WeatherManager from '#managers/weatherManager' export default class Weather extends BaseEvent { public listen(): void {