From 7c53af23804bfc87f7f300be8033d140d9b48eec Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Sat, 16 Apr 2022 13:40:25 +0300 Subject: [PATCH] implement chat logger --- .gitignore | 1 + src/server/game.ts | 9 ++++++ src/server/object/logger.ts | 55 +++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 src/server/object/logger.ts diff --git a/.gitignore b/.gitignore index 5d4f2f0..2bef561 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ dist/ node_modules/ /*.png /*.db +/*.log /config.toml diff --git a/src/server/game.ts b/src/server/game.ts index 6cda4ed..5a8eb3a 100644 --- a/src/server/game.ts +++ b/src/server/game.ts @@ -3,6 +3,7 @@ import { RequestHandler } from 'express'; import { IcyNetUser } from '../common/types/user'; import { CharacterPacket, PositionUpdatePacket } from '../common/types/packet'; import { Persistence } from './object/persistence'; +import { Logger } from './object/logger'; const PLACEHOLDER_USER = (socket: Socket): IcyNetUser => { const randomName = `player-${socket.id.substring(0, 8)}`; @@ -19,6 +20,7 @@ export class Game { private _connections: Socket[] = []; private _changedPlayers: number[] = []; private _db = new Persistence(); + private _log = new Logger(); constructor(private io: Server, private session: RequestHandler) {} @@ -32,6 +34,7 @@ export class Game { async initialize() { await this._db.initialize(); + this._log.initialize(); this.io.use((socket, next) => this.session(socket.request as any, {} as any, next as any), @@ -57,6 +60,7 @@ export class Game { if (user) { socket.broadcast.emit('playerjoin', publicUserInfo); + this._log.writeEvent('PlayerJoin', `<${user.display_name}:${user.id}>`); socket.data.user = user; socket.data.playerinfo = { @@ -89,6 +93,7 @@ export class Game { socket.on('chat-send', (raw) => { const message = raw.trim().substring(0, 280); + this._log.writeChat(user, message); this.io.emit('chat', { sender: publicUserInfo, message }); }); @@ -138,6 +143,10 @@ export class Game { if (user) { this.io.emit('playerleave', publicUserInfo); + this._log.writeEvent( + 'PlayerLeave', + `<${user.display_name}:${user.id}>`, + ); this._db.upsertPony(user, socket.data.playerinfo); } }); diff --git a/src/server/object/logger.ts b/src/server/object/logger.ts new file mode 100644 index 0000000..0506e15 --- /dev/null +++ b/src/server/object/logger.ts @@ -0,0 +1,55 @@ +import { join } from 'path'; +import fs from 'fs'; +import { IcyNetUser } from '../../common/types/user'; + +export class Logger { + private _stream!: fs.WriteStream; + + constructor(private _path = join(process.cwd(), 'chat.log')) {} + + initialize() { + this._stream = fs.createWriteStream(this._path, { + flags: 'a', + encoding: 'utf-8', + }); + } + + /** + * Write a chat message to the log file. + * @param user Sender + * @param message Message + */ + writeChat(user: IcyNetUser, message: string) { + const date = this._createTimestamp(new Date()); + const userStamp = `${user.display_name}:${user.id}`; + const fullStamp = `${date} <${userStamp}> ${message}`; + this._stream.write(`${fullStamp}\n`); + } + + /** + * Write a server event to the log file. + * @param event Event name + * @param message Event description + */ + writeEvent(event: string, message: string) { + const date = this._createTimestamp(new Date()); + this._stream.write(`${date} %EVENT:${event}% ${message}\n`); + } + + /** + * Returns timestamp in `YYYY/MM/DD HH:mm:ss` format. + * @param date Message time + * @returns Message timestamp + */ + private _createTimestamp(date: Date): string { + const az = (n: number) => n.toString().padStart(2, '0'); + const dateStamp = [date.getFullYear(), date.getMonth() + 1, date.getDate()] + .map(az) + .join('/'); + + const timeStamp = [date.getHours(), date.getMinutes(), date.getSeconds()] + .map(az) + .join(':'); + return `[${dateStamp} ${timeStamp}]`; + } +}