import { Server } from 'socket.io' import { TSocket } from '#application/types' import { writeFile } from 'node:fs/promises' import fs from 'fs/promises' import prisma from '#application/prisma' import sharp from 'sharp' import characterRepository from '#repositories/characterRepository' import { gameMasterLogger } from '#application/logger' import { getPublicPath } from '#application/storage' interface IObjectData { [key: string]: Buffer } export default class ObjectUploadEvent { constructor( private readonly io: Server, private readonly socket: TSocket ) {} public listen(): void { this.socket.on('gm:object:upload', this.handleObjectUpload.bind(this)) } private async handleObjectUpload(data: IObjectData, callback: (response: boolean) => void): Promise { try { const character = await characterRepository.getById(this.socket.characterId as number) if (!character) return callback(false) if (character.role !== 'gm') { return callback(false) } const public_folder = getPublicPath('objects') // Ensure the folder exists await fs.mkdir(public_folder, { recursive: true }) const uploadPromises = Object.entries(data).map(async ([key, objectData]) => { // Get image dimensions const metadata = await sharp(objectData).metadata() const width = metadata.width || 0 const height = metadata.height || 0 const object = await prisma.object.create({ data: { name: key, tags: [], originX: 0, originY: 0, frameWidth: width, frameHeight: height } }) const uuid = object.id const filename = `${uuid}.png` const finalFilePath = getPublicPath('objects', filename) await writeFile(finalFilePath, objectData) gameMasterLogger.info('gm:object:upload', `Object ${key} uploaded with id ${uuid}`) }) await Promise.all(uploadPromises) callback(true) } catch (error: any) { gameMasterLogger.error('gm:object:upload error', error.message) callback(false) } } }