Download Game! Currently 72 players and visitors. Last logged in:CorrelPaziIberiamsspSuzuki

Blitzer's Blog >> 72071

Back to blogs index
Posted: 05 Sep 2026 15:04 [ permalink ]
const WebSocket = require('ws');
const chokidar = require('chokidar');
const fs = require('fs/promises');
const path = require('path');
const { existsSync } = require('fs');
/ --- Configuration ---
const WS_URL = 'ws://localhost:1777';
const SYNC_DIR = path.resolve(__dirname, './gamelib/mesh/');
const WS_PREFIX = 'mesh/';
/ --- State & Locks ---
let ws;
let isConnected = false;
/ A map to track files currently being written by the WebSocket.
/ Key: Absolute file path, Value: Expiration timestamp (ms)
const writeLocks = new Map(); 
/ How long to ignore local Chokidar events after the WS writes a file.
/ 1500ms is generally safe to absorb OS-level file buffering events.
const LOCK_DURATION_MS = 1500; 
async function init() {
    // Ensure the sync directory exists before watching
    if (!existsSync(SYNC_DIR)) {
        await fs.mkdir(SYNC_DIR, { recursive: true });
        console.log(`[System] Created directory: ${SYNC_DIR}`);
    }
    startFileWatcher();
    connectWebSocket();
}
function startFileWatcher() {
    const watcher = chokidar.watch(SYNC_DIR, {
        persistent: true,
        ignoreInitial: true,
        awaitWriteFinish: {
            stabilityThreshold: 300,
            pollInterval: 100
        }
    });
    watcher.on('all', async (event, filePath) => {
        if (!isConnected) return;
        const lockExpiry = writeLocks.get(filePath);
        if (lockExpiry) {
            if (Date.now() < lockExpiry) {
                console.log(`[Watcher] Ignored echo event for:
${path.basename(filePath)}`);
                return;
            } else {
                writeLocks.delete(filePath); // Clean up expired lock
            }
        }
        const relativePath = path.relative(SYNC_DIR, filePath).replace(/\\/g,
'/');
        const dmzPath = `${WS_PREFIX}${relativePath}`;
        try {
            if (event === 'add' || event === 'change') {
                const fileData = await fs.readFile(filePath, { encoding:
'base64' });
                
                const payload = {
                    type: 'VFS_WRITE',
                    path: dmzPath,
                    data: fileData,
                    timestamp: Date.now()
                };
                ws.send(JSON.stringify(payload));
                console.log(`[FS -> WS] Broadcasted ${event}: ${dmzPath}`);
            } 
            else if (event === 'unlink') {
                // Handle deletions gracefully
                const payload = {
                    type: 'VFS_DELETE',
                    path: dmzPath,
                    timestamp: Date.now()
                };
                
                ws.send(JSON.stringify(payload));
                console.log(`[FS -> WS] Broadcasted delete: ${dmzPath}`);
            }
        } catch (err) {
            console.error(`[Watcher Error] Failed to process ${filePath}:`,
err.message);
        }
    });
}
function connectWebSocket() {
    console.log(`[Network] Connecting to ${WS_URL}...`);
    ws = new WebSocket(WS_URL);
    ws.on('open', () => {
        isConnected = true;
        console.log('[Network] Connected to DMZ server.');
    });
    ws.on('message', async (message) => {
        try {
            const msg = JSON.parse(message);
            if (msg.type === 'VFS_WRITE' && msg.path && msg.data) {
                await handleIncomingWrite(msg);
            } else if (msg.type === 'VFS_DELETE' && msg.path) {
                await handleIncomingDelete(msg);
            }
        } catch (err) {
            console.error('[Network Error] Failed to parse/handle message:',
err.message);
        }
    });
    ws.on('close', () => {
        isConnected = false;
        console.log('[Network] Disconnected. Reconnecting in 3 seconds...');
        setTimeout(connectWebSocket, 3000);
    });
    ws.on('error', (err) => {
        console.error('[Network Error]', err.message);
        ws.close();
    });
}
async function handleIncomingWrite(msg) {
    const relativeTarget = msg.path.replacenew RegExp(`^${WS_PREFIX}`), '');
    const absoluteTarget = path.join(SYNC_DIR, relativeTarget);
    if (!absoluteTarget.startsWith(SYNC_DIR)) {
        console.warn(`[Security] Blocked out-of-bounds write attempt:
${msg.path}`);
        return;
    }
    writeLocks.set(absoluteTarget, Date.now() + LOCK_DURATION_MS);
    await fs.mkdir(path.dirname(absoluteTarget), { recursive: true });
    const buffer = Buffer.from(msg.data, 'base64');
    await fs.writeFile(absoluteTarget, buffer);
    
    console.log(`[WS -> FS] Wrote incoming file: ${relativeTarget}`);
}
async function handleIncomingDelete(msg) {
    const relativeTarget = msg.path.replace(new RegExp(`^${WS_PREFIX}`), '');
    const absoluteTarget = path.join(SYNC_DIR, relativeTarget);
    if (!absoluteTarget.startsWith(SYNC_DIR)) return;
    // Set lock to prevent echoing the deletion back
    writeLocks.set(absoluteTarget, Date.now() + LOCK_DURATION_MS);
    try { if (existsSync(absoluteTarget)) { await fs.unlink(absoluteTarget);
      console.log(`[WS -> FS] Deleted incoming file: ${relativeTarget}`); }} 
    catch (err) { console.error(`[FS Error] Could not delete ${relativeTarget}:
`, err.message); }
}
/ Start the daemon
init();