#140 : Individual log files

This commit is contained in:
Dennis Postma 2024-09-21 15:39:50 +02:00
parent 90ac7728d9
commit 798bfac643
24 changed files with 136 additions and 135 deletions

20
package-lock.json generated
View File

@ -1141,9 +1141,9 @@
} }
}, },
"node_modules/engine.io": { "node_modules/engine.io": {
"version": "6.5.5", "version": "6.6.1",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.1.tgz",
"integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", "integrity": "sha512-NEpDCw9hrvBW+hVEOK4T7v0jFJ++KgtPl4jKFwsZVfG1XhS0dCrSb3VMb9gPAd7VAdW52VT1EnaNiU2vM8C0og==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/cookie": "^0.4.1", "@types/cookie": "^0.4.1",
@ -1789,9 +1789,9 @@
} }
}, },
"node_modules/nodemon": { "node_modules/nodemon": {
"version": "3.1.6", "version": "3.1.7",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.6.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz",
"integrity": "sha512-C8ymJbXpTTinxjWuMfMxw0rZhTn/r7ypSGldQyqPEgDEaVwAthqC0aodsMwontnAInN9TuPwRLeBoyhmfv+iSA==", "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2317,16 +2317,16 @@
} }
}, },
"node_modules/socket.io": { "node_modules/socket.io": {
"version": "4.7.5", "version": "4.8.0",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz",
"integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", "integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"accepts": "~1.3.4", "accepts": "~1.3.4",
"base64id": "~2.0.0", "base64id": "~2.0.0",
"cors": "~2.8.5", "cors": "~2.8.5",
"debug": "~4.3.2", "debug": "~4.3.2",
"engine.io": "~6.5.2", "engine.io": "~6.6.0",
"socket.io-adapter": "~2.5.2", "socket.io-adapter": "~2.5.2",
"socket.io-parser": "~4.2.4" "socket.io-parser": "~4.2.4"
}, },

View File

@ -4,7 +4,7 @@ import { Character } from '@prisma/client'
import CharacterRepository from '../../repositories/characterRepository' import CharacterRepository from '../../repositories/characterRepository'
import { ZCharacterCreate } from '../../utilities/zodTypes' import { ZCharacterCreate } from '../../utilities/zodTypes'
import prisma from '../../utilities/prisma' import prisma from '../../utilities/prisma'
import logger from '../../utilities/logger' import { gameLogger } from '../../utilities/logger'
export default function (socket: TSocket, io: Server) { export default function (socket: TSocket, io: Server) {
socket.on('character:create', async (data: any) => { socket.on('character:create', async (data: any) => {
@ -41,10 +41,10 @@ export default function (socket: TSocket, io: Server) {
socket.emit('character:create:success') socket.emit('character:create:success')
socket.emit('character:list', characters) socket.emit('character:list', characters)
logger.info('character:create success') gameLogger.info('character:create success')
} catch (error: any) { } catch (error: any) {
console.log(error) console.log(error)
logger.error(`character:create error: ${error.message}`) gameLogger.error(`character:create error: ${error.message}`)
return socket.emit('notification', { message: 'Could not create character. Please try again (later).' }) return socket.emit('notification', { message: 'Could not create character. Please try again (later).' })
} }
}) })

View File

@ -1,11 +1,9 @@
import { Server } from 'socket.io' import { Server } from 'socket.io'
import { ExtendedCharacter, TSocket } from '../../../utilities/types' import { TSocket } from '../../../utilities/types'
import { getArgs, isCommand } from '../../../utilities/chat' import { getArgs, isCommand } from '../../../utilities/chat'
import CharacterRepository from '../../../repositories/characterRepository'
import ZoneRepository from '../../../repositories/zoneRepository' import ZoneRepository from '../../../repositories/zoneRepository'
import CharacterManager from '../../../managers/characterManager' import CharacterManager from '../../../managers/characterManager'
import logger from '../../../utilities/logger' import { gameMasterLogger } from '../../../utilities/logger'
import prisma from '../../../utilities/prisma'
type TypePayload = { type TypePayload = {
message: string message: string
@ -76,11 +74,11 @@ export default class TeleportCommandEvent {
}) })
this.socket.emit('notification', { title: 'Server message', message: `You have been teleported to ${zone.name}` }) this.socket.emit('notification', { title: 'Server message', message: `You have been teleported to ${zone.name}` })
logger.info('teleport', `Character ${character.id} teleported to zone ${zone.id}`) gameMasterLogger.info('teleport', `Character ${character.id} teleported to zone ${zone.id}`)
callback(true) callback(true)
} catch (error: any) { } catch (error: any) {
logger.error(`Error in teleport command: ${error.message}`) gameMasterLogger.error(`Error in teleport command: ${error.message}`)
this.socket.emit('notification', { title: 'Server message', message: 'An error occurred while teleporting' }) this.socket.emit('notification', { title: 'Server message', message: 'An error occurred while teleporting' })
} }
} }

View File

@ -3,8 +3,7 @@ import { TSocket } from '../../utilities/types'
import CharacterRepository from '../../repositories/characterRepository' import CharacterRepository from '../../repositories/characterRepository'
import ZoneRepository from '../../repositories/zoneRepository' import ZoneRepository from '../../repositories/zoneRepository'
import { isCommand } from '../../utilities/chat' import { isCommand } from '../../utilities/chat'
import logger from '../../utilities/logger' import { gameLogger } from '../../utilities/logger'
import CharacterManager from '../../managers/characterManager'
type TypePayload = { type TypePayload = {
message: string message: string
@ -29,14 +28,14 @@ export default class ChatMessageEvent {
const character = await CharacterRepository.getByUserAndId(this.socket.user?.id as number, this.socket.characterId as number) const character = await CharacterRepository.getByUserAndId(this.socket.user?.id as number, this.socket.characterId as number)
if (!character) { if (!character) {
logger.error('chat:send_message error', 'Character not found') gameLogger.error('chat:send_message error', 'Character not found')
callback(false) callback(false)
return return
} }
const zone = await ZoneRepository.getById(character.zoneId) const zone = await ZoneRepository.getById(character.zoneId)
if (!zone) { if (!zone) {
logger.error('chat:send_message error', 'Zone not found') gameLogger.error('chat:send_message error', 'Zone not found')
callback(false) callback(false)
return return
} }
@ -48,7 +47,7 @@ export default class ChatMessageEvent {
message: data.message message: data.message
}) })
} catch (error: any) { } catch (error: any) {
logger.error('chat:send_message error', error.message) gameLogger.error('chat:send_message error', error.message)
callback(false) callback(false)
} }
} }

View File

@ -5,9 +5,8 @@ import path from 'path'
import fs from 'fs/promises' import fs from 'fs/promises'
import prisma from '../../../../utilities/prisma' import prisma from '../../../../utilities/prisma'
import sharp from 'sharp' import sharp from 'sharp'
import logger from '../../../../utilities/logger'
import CharacterManager from '../../../../managers/characterManager'
import characterRepository from '../../../../repositories/characterRepository' import characterRepository from '../../../../repositories/characterRepository'
import { gameMasterLogger } from '../../../../utilities/logger'
interface IObjectData { interface IObjectData {
[key: string]: Buffer [key: string]: Buffer
@ -58,14 +57,14 @@ export default class ObjectUploadEvent {
const finalFilePath = path.join(public_folder, filename) const finalFilePath = path.join(public_folder, filename)
await writeFile(finalFilePath, objectData) await writeFile(finalFilePath, objectData)
logger.info('gm:object:upload', `Object ${key} uploaded with id ${uuid}`) gameMasterLogger.info('gm:object:upload', `Object ${key} uploaded with id ${uuid}`)
}) })
await Promise.all(uploadPromises) await Promise.all(uploadPromises)
callback(true) callback(true)
} catch (error: any) { } catch (error: any) {
logger.error('gm:object:upload error', error.message) gameMasterLogger.error('gm:object:upload error', error.message)
callback(false) callback(false)
} }
} }

View File

@ -3,8 +3,8 @@ import { TSocket } from '../../../../utilities/types'
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
import prisma from '../../../../utilities/prisma' import prisma from '../../../../utilities/prisma'
import logger from '../../../../utilities/logger'
import CharacterManager from '../../../../managers/characterManager' import CharacterManager from '../../../../managers/characterManager'
import { gameMasterLogger } from '../../../../utilities/logger'
type Payload = { type Payload = {
id: string id: string
@ -34,10 +34,10 @@ export default class GMSpriteDeleteEvent {
await this.deleteSpriteFolder(data.id) await this.deleteSpriteFolder(data.id)
await this.deleteSpriteFromDatabase(data.id) await this.deleteSpriteFromDatabase(data.id)
logger.info(`Sprite ${data.id} deleted.`) gameMasterLogger.info(`Sprite ${data.id} deleted.`)
callback(true) callback(true)
} catch (error: any) { } catch (error: any) {
logger.error('gm:sprite:delete error', error.message) gameMasterLogger.error('gm:sprite:delete error', error.message)
callback(false) callback(false)
} }
} }

View File

@ -3,9 +3,8 @@ import fs from 'fs/promises'
import { Server } from 'socket.io' import { Server } from 'socket.io'
import { TSocket } from '../../../../utilities/types' import { TSocket } from '../../../../utilities/types'
import prisma from '../../../../utilities/prisma' import prisma from '../../../../utilities/prisma'
import logger from '../../../../utilities/logger'
import CharacterManager from '../../../../managers/characterManager'
import characterRepository from '../../../../repositories/characterRepository' import characterRepository from '../../../../repositories/characterRepository'
import { gameMasterLogger } from '../../../../utilities/logger'
type Payload = { type Payload = {
id: string id: string
@ -34,14 +33,14 @@ export default class GMTileDeleteEvent {
} }
try { try {
logger.info(`Deleting tile ${data.id}`) gameMasterLogger.info(`Deleting tile ${data.id}`)
await this.deleteTileFromDatabase(data.id) await this.deleteTileFromDatabase(data.id)
await this.deleteTileFile(data.id) await this.deleteTileFile(data.id)
logger.info(`Tile ${data.id} deleted successfully.`) gameMasterLogger.info(`Tile ${data.id} deleted successfully.`)
callback(true) callback(true)
} catch (error: any) { } catch (error: any) {
logger.error('gm:tile:delete error', error.message) gameMasterLogger.error('gm:tile:delete error', error.message)
callback(false) callback(false)
} }
} }
@ -62,7 +61,7 @@ export default class GMTileDeleteEvent {
if (error.code !== 'ENOENT') { if (error.code !== 'ENOENT') {
throw error throw error
} }
logger.warn(`File ${finalFilePath} does not exist.`) gameMasterLogger.warn(`File ${finalFilePath} does not exist.`)
} }
} }
} }

View File

@ -4,9 +4,8 @@ import { writeFile } from 'node:fs/promises'
import path from 'path' import path from 'path'
import fs from 'fs/promises' import fs from 'fs/promises'
import prisma from '../../../../utilities/prisma' import prisma from '../../../../utilities/prisma'
import CharacterManager from '../../../../managers/characterManager'
import characterRepository from '../../../../repositories/characterRepository' import characterRepository from '../../../../repositories/characterRepository'
import logger from '../../../../utilities/logger' import { gameMasterLogger } from '../../../../utilities/logger'
interface ITileData { interface ITileData {
[key: string]: Buffer [key: string]: Buffer
@ -48,7 +47,7 @@ export default function (socket: TSocket, io: Server) {
callback(true) callback(true)
} catch (error) { } catch (error) {
console.error('Error uploading tile:', error) gameMasterLogger.error('Error uploading tile:', error)
callback(false) callback(false)
} }
}) })

View File

@ -3,9 +3,8 @@ import { TSocket } from '../../../utilities/types'
import ZoneRepository from '../../../repositories/zoneRepository' import ZoneRepository from '../../../repositories/zoneRepository'
import { Zone } from '@prisma/client' import { Zone } from '@prisma/client'
import prisma from '../../../utilities/prisma' import prisma from '../../../utilities/prisma'
import CharacterManager from '../../../managers/characterManager'
import characterRepository from '../../../repositories/characterRepository' import characterRepository from '../../../repositories/characterRepository'
import logger from '../../../utilities/logger' import { gameMasterLogger } from '../../../utilities/logger'
type Payload = { type Payload = {
name: string name: string
@ -24,11 +23,11 @@ export default function (socket: TSocket, io: Server) {
if (!character) return if (!character) return
if (character.role !== 'gm') { if (character.role !== 'gm') {
logger.info(`User ${character.id} tried to create zone but is not a game master.`) gameMasterLogger.info(`User ${character.id} tried to create zone but is not a game master.`)
return return
} }
logger.info(`User ${character.id} has created a new zone via zone editor.`) gameMasterLogger.info(`User ${character.id} has created a new zone via zone editor.`)
let zoneList: Zone[] = [] let zoneList: Zone[] = []
try { try {

View File

@ -2,9 +2,8 @@ import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types' import { TSocket } from '../../../utilities/types'
import ZoneRepository from '../../../repositories/zoneRepository' import ZoneRepository from '../../../repositories/zoneRepository'
import prisma from '../../../utilities/prisma' import prisma from '../../../utilities/prisma'
import CharacterManager from '../../../managers/characterManager'
import characterRepository from '../../../repositories/characterRepository' import characterRepository from '../../../repositories/characterRepository'
import logger from '../../../utilities/logger' import { gameMasterLogger } from '../../../utilities/logger'
type Payload = { type Payload = {
zoneId: number zoneId: number
@ -21,11 +20,11 @@ export default function (socket: TSocket, io: Server) {
if (!character) return if (!character) return
if (character.role !== 'gm') { if (character.role !== 'gm') {
logger.info(`User ${character.id} tried to delete zone but is not a game master.`) gameMasterLogger.info(`User ${character.id} tried to delete zone but is not a game master.`)
return return
} }
logger.info(`User ${character.id} has deleted a zone via zone editor.`) gameMasterLogger.info(`User ${character.id} has deleted a zone via zone editor.`)
try { try {
const zone = await ZoneRepository.getById(data.zoneId) const zone = await ZoneRepository.getById(data.zoneId)

View File

@ -2,9 +2,8 @@ import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types' import { TSocket } from '../../../utilities/types'
import { Zone } from '@prisma/client' import { Zone } from '@prisma/client'
import ZoneRepository from '../../../repositories/zoneRepository' import ZoneRepository from '../../../repositories/zoneRepository'
import CharacterManager from '../../../managers/characterManager'
import characterRepository from '../../../repositories/characterRepository' import characterRepository from '../../../repositories/characterRepository'
import logger from '../../../utilities/logger' import { gameMasterLogger } from '../../../utilities/logger'
interface IPayload {} interface IPayload {}
@ -19,11 +18,11 @@ export default function (socket: TSocket, io: Server) {
if (!character) return if (!character) return
if (character.role !== 'gm') { if (character.role !== 'gm') {
logger.info(`User ${character.id} tried to list zones but is not a game master.`) gameMasterLogger.info(`User ${character.id} tried to list zones but is not a game master.`)
return return
} }
logger.info(`User ${character.id} has requested zone list via zone editor.`) gameMasterLogger.info(`User ${character.id} has requested zone list via zone editor.`)
try { try {
const zones = await ZoneRepository.getAll() const zones = await ZoneRepository.getAll()

View File

@ -1,10 +1,9 @@
import { Server } from 'socket.io' import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types' import { TSocket } from '../../../utilities/types'
import ZoneRepository from '../../../repositories/zoneRepository' import ZoneRepository from '../../../repositories/zoneRepository'
import { Character, Zone } from '@prisma/client' import { Zone } from '@prisma/client'
import CharacterManager from '../../../managers/characterManager'
import characterRepository from '../../../repositories/characterRepository' import characterRepository from '../../../repositories/characterRepository'
import logger from '../../../utilities/logger' import { gameMasterLogger } from '../../../utilities/logger'
interface IPayload { interface IPayload {
zoneId: number zoneId: number
@ -21,14 +20,14 @@ export default function (socket: TSocket, io: Server) {
if (!character) return if (!character) return
if (character.role !== 'gm') { if (character.role !== 'gm') {
logger.info(`User ${character!.id} tried to request zone but is not a game master.`) gameMasterLogger.info(`User ${character!.id} tried to request zone but is not a game master.`)
return return
} }
logger.info(`User ${character.id} has requested zone via zone editor.`) gameMasterLogger.info(`User ${character.id} has requested zone via zone editor.`)
if (!data.zoneId) { if (!data.zoneId) {
logger.info(`User ${character.id} tried to request zone but did not provide a zone id.`) gameMasterLogger.info(`User ${character.id} tried to request zone but did not provide a zone id.`)
return return
} }
@ -36,7 +35,7 @@ export default function (socket: TSocket, io: Server) {
const zone = await ZoneRepository.getById(data.zoneId) const zone = await ZoneRepository.getById(data.zoneId)
if (!zone) { if (!zone) {
logger.info(`User ${character.id} tried to request zone ${data.zoneId} but it does not exist.`) gameMasterLogger.info(`User ${character.id} tried to request zone ${data.zoneId} but it does not exist.`)
return return
} }

View File

@ -1,12 +1,11 @@
import { Server } from 'socket.io' import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types' import { TSocket } from '../../../utilities/types'
import ZoneRepository from '../../../repositories/zoneRepository' import ZoneRepository from '../../../repositories/zoneRepository'
import { Zone, ZoneEventTile, ZoneEventTileType, ZoneObject } from '@prisma/client' import { Zone, ZoneEventTileType, ZoneObject } from '@prisma/client'
import prisma from '../../../utilities/prisma' import prisma from '../../../utilities/prisma'
import zoneManager from '../../../managers/zoneManager' import zoneManager from '../../../managers/zoneManager'
import logger from '../../../utilities/logger'
import CharacterManager from '../../../managers/characterManager'
import characterRepository from '../../../repositories/characterRepository' import characterRepository from '../../../repositories/characterRepository'
import { gameMasterLogger } from '../../../utilities/logger'
interface IPayload { interface IPayload {
zoneId: number zoneId: number
@ -39,14 +38,14 @@ export default function (socket: TSocket, io: Server) {
if (!character) return if (!character) return
if (character.role !== 'gm') { if (character.role !== 'gm') {
logger.info(`User ${character.id} tried to update zone but is not a game master.`) gameMasterLogger.info(`User ${character.id} tried to update zone but is not a game master.`)
return return
} }
logger.info(`User ${character.id} has updated zone via zone editor.`) gameMasterLogger.info(`User ${character.id} has updated zone via zone editor.`)
if (!data.zoneId) { if (!data.zoneId) {
logger.info(`User ${character.id} tried to update zone but did not provide a zone id.`) gameMasterLogger.info(`User ${character.id} tried to update zone but did not provide a zone id.`)
return return
} }
@ -54,7 +53,7 @@ export default function (socket: TSocket, io: Server) {
let zone = await ZoneRepository.getById(data.zoneId) let zone = await ZoneRepository.getById(data.zoneId)
if (!zone) { if (!zone) {
logger.info(`User ${character.id} tried to update zone ${data.zoneId} but it does not exist.`) gameMasterLogger.info(`User ${character.id} tried to update zone ${data.zoneId} but it does not exist.`)
return return
} }
@ -108,7 +107,7 @@ export default function (socket: TSocket, io: Server) {
zone = await ZoneRepository.getById(data.zoneId) zone = await ZoneRepository.getById(data.zoneId)
if (!zone) { if (!zone) {
logger.info(`User ${character.id} tried to update zone ${data.zoneId} but it does not exist.`) gameMasterLogger.info(`User ${character.id} tried to update zone ${data.zoneId} but it does not exist.`)
return return
} }
@ -117,7 +116,7 @@ export default function (socket: TSocket, io: Server) {
zoneManager.unloadZone(data.zoneId) zoneManager.unloadZone(data.zoneId)
await zoneManager.loadZone(zone) await zoneManager.loadZone(zone)
} catch (error: any) { } catch (error: any) {
logger.error(`Error updating zone: ${error.message}`) gameMasterLogger.error(`Error updating zone: ${error.message}`)
} }
}) })
} }

View File

@ -1,10 +1,9 @@
import { Server } from 'socket.io' import { Server } from 'socket.io'
import { ExtendedCharacter, TSocket } from '../../utilities/types' import { TSocket } from '../../utilities/types'
import ZoneRepository from '../../repositories/zoneRepository' import ZoneRepository from '../../repositories/zoneRepository'
import ZoneManager from '../../managers/zoneManager'
import { Character, Zone } from '@prisma/client' import { Character, Zone } from '@prisma/client'
import logger from '../../utilities/logger'
import CharacterManager from '../../managers/characterManager' import CharacterManager from '../../managers/characterManager'
import { gameLogger } from '../../utilities/logger'
interface IPayload { interface IPayload {
zoneId: number zoneId: number
@ -58,7 +57,7 @@ export default function (socket: TSocket, io: Server) {
// send over zone and characters to socket // send over zone and characters to socket
callback({ zone, characters: CharacterManager.getCharactersInZone(zone) }) callback({ zone, characters: CharacterManager.getCharactersInZone(zone) })
} catch (error: any) { } catch (error: any) {
logger.error(`Error requesting zone: ${error.message}`) gameLogger.error(`Error requesting zone: ${error.message}`)
socket.disconnect() socket.disconnect()
} }
}) })

View File

@ -2,7 +2,7 @@ import { Server } from 'socket.io'
import { TSocket } from '../../utilities/types' import { TSocket } from '../../utilities/types'
import ZoneRepository from '../../repositories/zoneRepository' import ZoneRepository from '../../repositories/zoneRepository'
import CharacterManager from '../../managers/characterManager' import CharacterManager from '../../managers/characterManager'
import logger from '../../utilities/logger' import { gameLogger } from '../../utilities/logger'
export default class ZoneLeaveEvent { export default class ZoneLeaveEvent {
constructor( constructor(
@ -18,19 +18,19 @@ export default class ZoneLeaveEvent {
try { try {
const character = CharacterManager.getCharacterFromSocket(this.socket); const character = CharacterManager.getCharacterFromSocket(this.socket);
if (!character) { if (!character) {
logger.error('zone:character:leave error', 'Character not found') gameLogger.error('zone:character:leave error', 'Character not found')
return return
} }
if (!character.zoneId) { if (!character.zoneId) {
logger.error('zone:character:leave error', 'Character not in a zone') gameLogger.error('zone:character:leave error', 'Character not in a zone')
return return
} }
const zone = await ZoneRepository.getById(character.zoneId) const zone = await ZoneRepository.getById(character.zoneId)
if (!zone) { if (!zone) {
logger.error('zone:character:leave error', 'Zone not found') gameLogger.error('zone:character:leave error', 'Zone not found')
return return
} }
@ -42,9 +42,9 @@ export default class ZoneLeaveEvent {
// remove character from zone manager // remove character from zone manager
await CharacterManager.removeCharacter(character) await CharacterManager.removeCharacter(character)
logger.info('zone:character:leave', `Character ${character.id} left zone ${zone.id}`) gameLogger.info('zone:character:leave', `Character ${character.id} left zone ${zone.id}`)
} catch (error: any) { } catch (error: any) {
logger.error('zone:character:leave error', error.message) gameLogger.error('zone:character:leave error', error.message)
} }
} }
} }

View File

@ -5,10 +5,8 @@ import { ZoneEventTileService } from '../../services/zoneEventTileService'
import prisma from '../../utilities/prisma' import prisma from '../../utilities/prisma'
import { ZoneEventTile, ZoneEventTileTeleport } from '@prisma/client' import { ZoneEventTile, ZoneEventTileTeleport } from '@prisma/client'
import Rotation from '../../utilities/character/rotation' import Rotation from '../../utilities/character/rotation'
import logger from '../../utilities/logger'
import CharacterManager from '../../managers/characterManager' import CharacterManager from '../../managers/characterManager'
import zoneManager from '../../managers/zoneManager' import { gameLogger } from '../../utilities/logger'
import ZoneManager from '../../managers/zoneManager'
export type ZoneEventTileWithTeleport = ZoneEventTile & { export type ZoneEventTileWithTeleport = ZoneEventTile & {
teleport: ZoneEventTileTeleport teleport: ZoneEventTileTeleport
@ -35,12 +33,12 @@ export default class CharacterMove {
private async handleCharacterMove({ positionX, positionY }: { positionX: number; positionY: number }): Promise<void> { private async handleCharacterMove({ positionX, positionY }: { positionX: number; positionY: number }): Promise<void> {
let character = CharacterManager.getCharacterFromSocket(this.socket) let character = CharacterManager.getCharacterFromSocket(this.socket)
if (!character) { if (!character) {
logger.error('character:move error', 'Character not found') gameLogger.error('character:move error', 'Character not found')
return return
} }
if (!character) { if (!character) {
logger.error('character:move error', 'character has not been initialized?') gameLogger.error('character:move error', 'character has not been initialized?')
return return
} }
@ -127,7 +125,7 @@ export default class CharacterMove {
private async handleZoneEventTile(zoneEventTile: ZoneEventTileWithTeleport): Promise<void> { private async handleZoneEventTile(zoneEventTile: ZoneEventTileWithTeleport): Promise<void> {
const character = CharacterManager.getCharacterFromSocket(this.socket) const character = CharacterManager.getCharacterFromSocket(this.socket)
if (!character) { if (!character) {
logger.error('character:move error', 'Character not found') gameLogger.error('character:move error', 'Character not found')
return return
} }

View File

@ -1,5 +1,5 @@
import { User } from '@prisma/client' import { User } from '@prisma/client'
import logger from '../utilities/logger' import { appLogger } from '../utilities/logger'
type TLoggedInUsers = { type TLoggedInUsers = {
users: User[] users: User[]
@ -10,7 +10,7 @@ class UserManager {
// Method to initialize user manager // Method to initialize user manager
public async boot() { public async boot() {
logger.info('User manager loaded') appLogger.info('User manager loaded')
} }
// Function that adds user to logged in users // Function that adds user to logged in users

View File

@ -1,11 +1,9 @@
import { Zone, ZoneEventTileTeleport, ZoneEventTileType } from '@prisma/client' import { Zone } from '@prisma/client'
import ZoneRepository from '../repositories/zoneRepository' import ZoneRepository from '../repositories/zoneRepository'
import ZoneService from '../services/zoneService' import ZoneService from '../services/zoneService'
import logger from '../utilities/logger'
import LoadedZone from '../models/loadedZone' import LoadedZone from '../models/loadedZone'
import zoneRepository from '../repositories/zoneRepository' import zoneRepository from '../repositories/zoneRepository'
import { beforeEach } from 'node:test' import { gameMasterLogger } from '../utilities/logger'
import prisma from '../utilities/prisma'
class ZoneManager { class ZoneManager {
private loadedZones: LoadedZone[] = [] private loadedZones: LoadedZone[] = []
@ -23,7 +21,7 @@ class ZoneManager {
await this.loadZone(zone) await this.loadZone(zone)
} }
logger.info('Zone manager loaded') gameMasterLogger.info('Zone manager loaded')
} }
public async getZoneAssets(zone: Zone): Promise<ZoneAssets> { public async getZoneAssets(zone: Zone): Promise<ZoneAssets> {
@ -46,13 +44,13 @@ class ZoneManager {
const loadedZone = new LoadedZone(zone) const loadedZone = new LoadedZone(zone)
this.loadedZones.push(loadedZone) this.loadedZones.push(loadedZone)
await this.getZoneAssets(zone) await this.getZoneAssets(zone)
logger.info(`Zone ID ${zone.id} loaded`) gameMasterLogger.info(`Zone ID ${zone.id} loaded`)
} }
// Method to handle individual zoneEditor unloading // Method to handle individual zoneEditor unloading
public unloadZone(zoneId: number) { public unloadZone(zoneId: number) {
this.loadedZones = this.loadedZones.filter((loadedZone) => loadedZone.getZone().id !== zoneId) this.loadedZones = this.loadedZones.filter((loadedZone) => loadedZone.getZone().id !== zoneId)
logger.info(`Zone ID ${zoneId} unloaded`) gameMasterLogger.info(`Zone ID ${zoneId} unloaded`)
} }
// Getter for loaded zones // Getter for loaded zones

View File

@ -3,7 +3,7 @@ import { TSocket } from '../utilities/types'
import config from '../utilities/config' import config from '../utilities/config'
import UserRepository from '../repositories/userRepository' import UserRepository from '../repositories/userRepository'
import { User } from '@prisma/client' import { User } from '@prisma/client'
import logger from '../utilities/logger' import { gameLogger } from '../utilities/logger'
/** /**
* Socket io jwt auth middleware * Socket io jwt auth middleware
@ -12,7 +12,7 @@ import logger from '../utilities/logger'
*/ */
export async function Authentication(socket: TSocket, next: any) { export async function Authentication(socket: TSocket, next: any) {
if (!socket.request.headers.cookie) { if (!socket.request.headers.cookie) {
logger.warn('No cookie provided') gameLogger.warn('No cookie provided')
return next(new Error('Authentication error')) return next(new Error('Authentication error'))
} }
@ -33,7 +33,7 @@ export async function Authentication(socket: TSocket, next: any) {
if (token) { if (token) {
verify(token, config.JWT_SECRET, async (err: any, decoded: any) => { verify(token, config.JWT_SECRET, async (err: any, decoded: any) => {
if (err) { if (err) {
logger.error('Invalid token') gameLogger.error('Invalid token')
return next(new Error('Authentication error')) return next(new Error('Authentication error'))
} }
@ -41,7 +41,7 @@ export async function Authentication(socket: TSocket, next: any) {
next() next()
}) })
} else { } else {
logger.warn('No token provided') gameLogger.warn('No token provided')
return next(new Error('Authentication error')) return next(new Error('Authentication error'))
} }
} }

View File

@ -1,14 +1,14 @@
import { Zone, ZoneEventTile, ZoneEventTileTeleport, ZoneEventTileType, ZoneObject } from '@prisma/client' import { Zone, ZoneEventTile, ZoneEventTileType, ZoneObject } from '@prisma/client'
import prisma from '../utilities/prisma' import prisma from '../utilities/prisma'
import logger from '../utilities/logger'
import { ZoneEventTileWithTeleport } from '../events/zone/characterMove' import { ZoneEventTileWithTeleport } from '../events/zone/characterMove'
import { appLogger } from '../utilities/logger'
class ZoneRepository { class ZoneRepository {
async getFirst(): Promise<Zone | null> { async getFirst(): Promise<Zone | null> {
try { try {
return await prisma.zone.findFirst() return await prisma.zone.findFirst()
} catch (error: any) { } catch (error: any) {
logger.error(`Failed to get first zone: ${error.message}`) appLogger.error(`Failed to get first zone: ${error.message}`)
return null return null
} }
} }
@ -17,7 +17,7 @@ class ZoneRepository {
try { try {
return await prisma.zone.findMany() return await prisma.zone.findMany()
} catch (error: any) { } catch (error: any) {
logger.error(`Failed to get all zone: ${error.message}`) appLogger.error(`Failed to get all zone: ${error.message}`)
return [] return []
} }
} }
@ -43,7 +43,7 @@ class ZoneRepository {
} }
}) })
} catch (error: any) { } catch (error: any) {
logger.error(`Failed to get zone by id: ${error.message}`) appLogger.error(`Failed to get zone by id: ${error.message}`)
return null return null
} }
} }
@ -56,7 +56,7 @@ class ZoneRepository {
} }
}) })
} catch (error: any) { } catch (error: any) {
logger.error(`Failed to get zone event tiles: ${error.message}`) appLogger.error(`Failed to get zone event tiles: ${error.message}`)
return [] return []
} }
} }
@ -71,7 +71,7 @@ class ZoneRepository {
include: { teleport: true } include: { teleport: true }
})) as unknown as ZoneEventTileWithTeleport[] })) as unknown as ZoneEventTileWithTeleport[]
} catch (error: any) { } catch (error: any) {
logger.error(`Failed to get zone event tiles: ${error.message}`) appLogger.error(`Failed to get zone event tiles: ${error.message}`)
return [] return []
} }
} }
@ -84,7 +84,7 @@ class ZoneRepository {
} }
}) })
} catch (error: any) { } catch (error: any) {
logger.error(`Failed to get zone objects: ${error.message}`) appLogger.error(`Failed to get zone objects: ${error.message}`)
return [] return []
} }
} }

View File

@ -13,7 +13,7 @@ import UserManager from './managers/userManager'
import { Authentication } from './middleware/authentication' import { Authentication } from './middleware/authentication'
// import CommandManager from './managers/CommandManager' // import CommandManager from './managers/CommandManager'
import { Dirent } from 'node:fs' import { Dirent } from 'node:fs'
import logger from './utilities/logger' import { appLogger, watchLogs } from './utilities/logger'
import CharacterManager from './managers/characterManager' import CharacterManager from './managers/characterManager'
export class Server { export class Server {
@ -39,31 +39,22 @@ export class Server {
*/ */
public async start() { public async start() {
// Read log file and print to console for debugging // Read log file and print to console for debugging
const logFile = path.join(__dirname, '../logs/app.log') watchLogs()
fs.watchFile(logFile, (curr, prev) => {
if (curr.size > prev.size) {
const stream = fs.createReadStream(logFile, { start: prev.size, end: curr.size })
stream.on('data', (chunk) => {
console.log(chunk.toString())
})
}
})
// Check prisma connection // Check prisma connection
try { try {
await prisma.$connect() await prisma.$connect()
logger.info('Database connected') appLogger.info('Database connected')
} catch (error: any) { } catch (error: any) {
logger.error(`Database connection failed: ${error.message}`) appLogger.error(`Database connection failed: ${error.message}`)
} }
// Start the server // Start the server
try { try {
this.http.listen(config.PORT, config.HOST) this.http.listen(config.PORT, config.HOST)
logger.info(`Socket.IO running on port ${config.PORT}`) appLogger.info(`Socket.IO running on port ${config.PORT}`)
} catch (error: any) { } catch (error: any) {
logger.error(`Socket.IO failed to start: ${error.message}`) appLogger.error(`Socket.IO failed to start: ${error.message}`)
} }
// Add http API routes // Add http API routes
@ -95,7 +86,7 @@ export class Server {
try { try {
await this.loadEventHandlers(eventsPath, socket) await this.loadEventHandlers(eventsPath, socket)
} catch (error: any) { } catch (error: any) {
logger.error(`Failed to load event handlers: ${error.message}`) appLogger.error(`Failed to load event handlers: ${error.message}`)
} }
} }
@ -121,10 +112,10 @@ export class Server {
module.default(socket, this.io) module.default(socket, this.io)
} }
} else { } else {
logger.warn(`Unrecognized export in ${file.name}`) appLogger.warn(`Unrecognized export in ${file.name}`)
} }
} catch (error: any) { } catch (error: any) {
logger.error(`Error loading event handler ${file.name}: ${error.message}`) appLogger.error(`Error loading event handler ${file.name}: ${error.message}`)
} }
} }
} }
@ -135,4 +126,4 @@ export class Server {
const server = new Server() const server = new Server()
server.start() server.start()
console.log('Server started') appLogger.info('Server started')

View File

@ -1,9 +1,8 @@
import { ExtendedCharacter } from '../../utilities/types' import { ExtendedCharacter } from '../../utilities/types'
import { AStar } from '../../utilities/character/aStar' import { AStar } from '../../utilities/character/aStar'
import ZoneManager from '../../managers/zoneManager' import ZoneManager from '../../managers/zoneManager'
import prisma from '../../utilities/prisma'
import Rotation from '../../utilities/character/rotation' import Rotation from '../../utilities/character/rotation'
import logger from '../../utilities/logger' import { gameLogger } from '../../utilities/logger'
export class CharacterMoveService { export class CharacterMoveService {
public updatePosition(character: ExtendedCharacter, position: { x: number; y: number }, newZoneId?: number) { public updatePosition(character: ExtendedCharacter, position: { x: number; y: number }, newZoneId?: number) {
@ -28,7 +27,7 @@ export class CharacterMoveService {
public async calculatePath(character: ExtendedCharacter, targetX: number, targetY: number): Promise<Array<{ x: number; y: number }> | null> { public async calculatePath(character: ExtendedCharacter, targetX: number, targetY: number): Promise<Array<{ x: number; y: number }> | null> {
const grid = await ZoneManager.getZoneById(character.zoneId)?.getGrid() const grid = await ZoneManager.getZoneById(character.zoneId)?.getGrid()
if (!grid?.length) { if (!grid?.length) {
logger.error('character:move error', 'Grid not found or empty') gameLogger.error('character:move error', 'Grid not found or empty')
return null return null
} }

View File

@ -9,9 +9,9 @@ import tileRepository from '../repositories/tileRepository'
import objectRepository from '../repositories/objectRepository' import objectRepository from '../repositories/objectRepository'
import spriteRepository from '../repositories/spriteRepository' import spriteRepository from '../repositories/spriteRepository'
import fs from 'fs' import fs from 'fs'
import logger from './logger'
import zoneRepository from '../repositories/zoneRepository' import zoneRepository from '../repositories/zoneRepository'
import zoneManager from '../managers/zoneManager' import zoneManager from '../managers/zoneManager'
import { httpLogger } from './logger'
async function addHttpRoutes(app: Application) { async function addHttpRoutes(app: Application) {
/** /**
@ -118,13 +118,13 @@ async function addHttpRoutes(app: Application) {
} }
if (!fs.existsSync(assetPath)) { if (!fs.existsSync(assetPath)) {
logger.error(`File not found: ${assetPath}`) httpLogger.error(`File not found: ${assetPath}`)
return res.status(404).send('Asset not found') return res.status(404).send('Asset not found')
} }
res.sendFile(assetPath, (err) => { res.sendFile(assetPath, (err) => {
if (err) { if (err) {
logger.error('Error sending file:', err) httpLogger.error('Error sending file:', err)
res.status(500).send('Error downloading the asset') res.status(500).send('Error downloading the asset')
} }
}) })
@ -179,7 +179,7 @@ async function addHttpRoutes(app: Application) {
return res.status(400).json({ message: 'Failed to register user' }) return res.status(400).json({ message: 'Failed to register user' })
}) })
logger.info('Web routes added') httpLogger.info('Web routes added')
} }
export { addHttpRoutes } export { addHttpRoutes }

View File

@ -1,11 +1,17 @@
import pino from 'pino' import pino from 'pino'
import fs from 'fs'
import path from 'path'
const logger = pino({ // Array of log types
const LOG_TYPES = ['http', 'game', 'gameMaster', 'app'] as const
type LogType = typeof LOG_TYPES[number]
const createLogger = (name: LogType) => pino({
level: process.env.LOG_LEVEL || 'debug', level: process.env.LOG_LEVEL || 'debug',
transport: { transport: {
target: 'pino/file', target: 'pino/file',
options: { options: {
destination: './logs/app.log', destination: `./logs/${name}.log`,
mkdir: true mkdir: true
} }
}, },
@ -15,7 +21,28 @@ const logger = pino({
} }
}, },
timestamp: pino.stdTimeFunctions.isoTime, timestamp: pino.stdTimeFunctions.isoTime,
base: null // This will prevent hostname and pid from being included base: null
}) })
export default logger // Create logger instances
const loggers = Object.fromEntries(
LOG_TYPES.map(type => [type, createLogger(type)])
) as Record<LogType, ReturnType<typeof createLogger>>
const watchLogs = () => {
LOG_TYPES.forEach(type => {
const logFile = path.join(__dirname, '../../logs', `${type}.log`)
fs.watchFile(logFile, (curr, prev) => {
if (curr.size > prev.size) {
const stream = fs.createReadStream(logFile, { start: prev.size, end: curr.size })
stream.on('data', (chunk) => {
console.log(`[${type}] \n ${chunk.toString()}`)
})
}
})
})
}
export const { http: httpLogger, game: gameLogger, gameMaster: gameMasterLogger, app: appLogger } = loggers
export { watchLogs }