84 lines
2.5 KiB
JavaScript
84 lines
2.5 KiB
JavaScript
const path = require('path');
|
|
const http = require('http');
|
|
const express = require('express');
|
|
const dgram = require('dgram');
|
|
const { WebSocketServer } = require('ws');
|
|
|
|
const HTTP_PORT = process.env.PORT || 3000;
|
|
// UDP settings
|
|
// Default broadcast; override with unicast address via UDP_ADDR if you have a single receiver
|
|
const UDP_BROADCAST_PORT = Number(process.env.UDP_PORT) || 4210;
|
|
const UDP_BROADCAST_ADDR = process.env.UDP_ADDR || '255.255.255.255';
|
|
|
|
// NeoPixel frame properties for basic validation/logging (no transformation here)
|
|
const MATRIX_WIDTH = Number(process.env.MATRIX_WIDTH) || 16;
|
|
const MATRIX_HEIGHT = Number(process.env.MATRIX_HEIGHT) || 16;
|
|
const BYTES_PER_PIXEL = 3; // GRB without alpha
|
|
|
|
const app = express();
|
|
app.use(express.static(path.join(__dirname, 'public')));
|
|
|
|
const server = http.createServer(app);
|
|
const wss = new WebSocketServer({ server, path: '/ws' });
|
|
|
|
const udpSocket = dgram.createSocket('udp4');
|
|
udpSocket.on('error', (err) => {
|
|
console.error('[UDP] error:', err);
|
|
});
|
|
udpSocket.bind(() => {
|
|
try {
|
|
udpSocket.setBroadcast(true);
|
|
console.log(`[UDP] Ready to broadcast on ${UDP_BROADCAST_ADDR}:${UDP_BROADCAST_PORT}`);
|
|
} catch (e) {
|
|
console.error('[UDP] setBroadcast failed:', e);
|
|
}
|
|
});
|
|
|
|
wss.on('connection', (ws, req) => {
|
|
const clientAddress = req?.socket?.remoteAddress || 'unknown';
|
|
console.log(`[WS] Client connected: ${clientAddress}`);
|
|
|
|
ws.on('message', (data) => {
|
|
const bufferToSend = Buffer.isBuffer(data)
|
|
? data
|
|
: (data instanceof ArrayBuffer ? Buffer.from(data) : Buffer.from(String(data)));
|
|
|
|
const expectedSize = MATRIX_WIDTH * MATRIX_HEIGHT * BYTES_PER_PIXEL;
|
|
if (bufferToSend.length !== expectedSize) {
|
|
console.warn(`[WS] Unexpected frame size: ${bufferToSend.length} bytes (expected ${expectedSize}).`);
|
|
}
|
|
|
|
const hexPayload = bufferToSend.toString('hex');
|
|
const udpPayload = Buffer.from(`RAW:${hexPayload}`, 'ascii');
|
|
|
|
udpSocket.send(
|
|
udpPayload,
|
|
UDP_BROADCAST_PORT,
|
|
UDP_BROADCAST_ADDR,
|
|
(err) => {
|
|
if (err) {
|
|
console.error('[UDP] send error:', err.message);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
|
|
ws.on('close', () => {
|
|
console.log('[WS] Client disconnected');
|
|
});
|
|
|
|
ws.on('error', (err) => {
|
|
console.error('[WS] error:', err.message);
|
|
});
|
|
});
|
|
|
|
server.listen(HTTP_PORT, () => {
|
|
console.log(`Server listening on http://localhost:${HTTP_PORT}`);
|
|
});
|
|
|
|
process.on('SIGINT', () => {
|
|
console.log('Shutting down...');
|
|
try { udpSocket.close(); } catch {}
|
|
try { server.close(() => process.exit(0)); } catch {}
|
|
});
|