Files
discord-rpg-concept/bot/lib/loaders/EventLoader.ts
2026-01-08 16:09:26 +01:00

86 lines
2.8 KiB
TypeScript

import { readdir } from "node:fs/promises";
import { join } from "node:path";
import type { Event } from "@shared/lib/types";
import type { LoadResult } from "./types";
import type { Client } from "../BotClient";
/**
* Handles loading events from the file system
*/
export class EventLoader {
private client: Client;
constructor(client: Client) {
this.client = client;
}
/**
* Load events from a directory recursively
*/
async loadFromDirectory(dir: string, reload: boolean = false): Promise<LoadResult> {
const result: LoadResult = { loaded: 0, skipped: 0, errors: [] };
await this.scanDirectory(dir, reload, result);
return result;
}
/**
* Recursively scan directory for event files
*/
private async scanDirectory(dir: string, reload: boolean, result: LoadResult): Promise<void> {
try {
const files = await readdir(dir, { withFileTypes: true });
for (const file of files) {
const filePath = join(dir, file.name);
if (file.isDirectory()) {
await this.scanDirectory(filePath, reload, result);
continue;
}
if (!file.name.endsWith('.ts') && !file.name.endsWith('.js')) continue;
await this.loadEventFile(filePath, reload, result);
}
} catch (error) {
console.error(`Error reading directory ${dir}:`, error);
result.errors.push({ file: dir, error });
}
}
/**
* Load a single event file
*/
private async loadEventFile(filePath: string, reload: boolean, result: LoadResult): Promise<void> {
try {
const importPath = reload ? `${filePath}?t=${Date.now()}` : filePath;
const eventModule = await import(importPath);
const event = eventModule.default;
if (this.isValidEvent(event)) {
if (event.once) {
this.client.once(event.name, (...args) => event.execute(...args));
} else {
this.client.on(event.name, (...args) => event.execute(...args));
}
console.log(`Loaded event: ${event.name}`);
result.loaded++;
} else {
console.warn(`Skipping invalid event in ${filePath}`);
result.skipped++;
}
} catch (error) {
console.error(`Failed to load event from ${filePath}:`, error);
result.errors.push({ file: filePath, error });
}
}
/**
* Type guard to validate event structure
*/
private isValidEvent(event: any): event is Event<any> {
return event && typeof event === 'object' && 'name' in event && 'execute' in event;
}
}