57 lines
2.2 KiB
JavaScript
57 lines
2.2 KiB
JavaScript
/*
|
|
! /server/actions.js
|
|
? Dynamic action loader for Socket.IO events using a recursive file system scan.
|
|
*/
|
|
|
|
// % imports
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
// % Target directory where the actual action files reside
|
|
const actionsDir = path.join(__dirname, '..', 'actions');
|
|
|
|
// $ debug-output
|
|
console.info('[Paths] Actions:', actionsDir);
|
|
|
|
/*
|
|
$ Recursive function to load action files and build a flat map for direct dot-notation access
|
|
= Maps all JavaScript files inside the actions directory into a flat key-value structure (e.g. 'chat.message').
|
|
|
|
^ Usage in WebSocket (Socket.io) Handlers:
|
|
?? import actions from './actions/index.js';
|
|
? Example: "socket.on('chat.message', (data) => actions['chat.message'](socket, data));"
|
|
? Example: "socket.on('system.ping', () => actions['system.ping'](socket));"
|
|
*/
|
|
|
|
async function loadActions(dir = actionsDir, baseDir = actionsDir, actionsObj = {}) {
|
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
|
|
for (const entry of entries) {
|
|
const fullPath = path.join(dir, entry.name);
|
|
|
|
if (entry.isDirectory()) {
|
|
// ~ Pass the main object (actionsObj) further down recursively
|
|
await loadActions(fullPath, baseDir, actionsObj);
|
|
} else if (entry.isFile() && entry.name !== 'index.js' && !entry.name.startsWith('.') && entry.name.endsWith('.js')) {
|
|
// ~ Calculate the relative path from the root directory
|
|
const relativePath = path.relative(baseDir, fullPath);
|
|
const parts = relativePath.split(path.sep).map(p => p.replace(/\.js$/, ''));
|
|
|
|
// ~ Import the module
|
|
const fileUrl = pathToFileURL(fullPath).href;
|
|
const module = await import(fileUrl);
|
|
|
|
// ~ Map the module directly as a flat string key (e.g. "chat.message") into the main object
|
|
const eventName = parts.join('.');
|
|
actionsObj[eventName] = module.default || module;
|
|
}
|
|
}
|
|
return actionsObj;
|
|
}
|
|
|
|
// $ Initialize asynchronously and export the loaded actions object
|
|
const actions = await loadActions();
|
|
export default actions; |