UNPKG

ws2801-webserver

Version:

A ready-to-use webserver for the WS2801-Pi package.

221 lines (220 loc) 10.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Ws2801Webserver = void 0; const child_process_1 = require("child_process"); const path_1 = __importDefault(require("path")); const ws2801_pi_1 = __importDefault(require("ws2801-pi")); const auth_service_1 = require("./auth-service"); const config_1 = require("./config/config"); const led_strip_validation_1 = require("./led-strip-validation"); const socket_io_server_1 = require("./socket-io-server"); const webserver_1 = require("./webserver"); class Ws2801Webserver { constructor(config, ledController) { this.config = config ? config : config_1.DefaultConfig; if (!ledController && !this.config.amountOfLeds) { throw new Error(`Either a ledController must be provided or the amount of leds must be provided via config!`); } this.ledController = ledController ? ledController : new ws2801_pi_1.default(this.config.amountOfLeds); this.webserver = new webserver_1.Webserver(this.config.port, this.config.logRequests === true); this.authService = new auth_service_1.AuthService(this.config, this.webserver); this.socketIoServer = new socket_io_server_1.SocketIoServer(this.webserver.getHttpServer()); } start() { if (this.config.useAuth) { this.authService.start(); } this.addRoutes(); // this.addSocketIoListeners(); this.addSocketIoEmitters(); this.webserver.start(); } stop() { this.authService.stop(); this.webserver.stop(); } getLedController() { return this.ledController; } getExpressServer() { return this.webserver.getExpressServer(); } addRoutes() { this.webserver.addGetRoute('/login-required', this.loginRequired.bind(this)); this.webserver.addGetRoute('/led-strip', this.getLedStrip.bind(this)); this.webserver.addPostRoute('/led-strip/fill', this.fillLedStrip.bind(this)); this.webserver.addPostRoute('/led-strip/clear', this.clearLedStrip.bind(this)); this.webserver.addPostRoute('/led-strip/led/:ledIndex/set', this.setSingleLedColor.bind(this)); this.webserver.addPostRoute('/led-strip/brightness/set', this.setBrightness.bind(this)); this.webserver.addGetRoute('/led-strip/brightness', this.getBrightness.bind(this)); this.webserver.addPostRoute('/led-strip/set', this.setLedStrip.bind(this)); this.webserver.addPostRoute('/led-strip/animation/start', this.startAnimation.bind(this)); this.webserver.addDeleteRoute('/led-strip/animation/stop', this.stopAnimation.bind(this)); this.webserver.addGetRoute('/led-strip/animation/finished', this.waitForAnimationToFinish.bind(this)); } // private addSocketIoListeners(): void { // } addSocketIoEmitters() { this.ledController.onLedStripChanged((ledStrip) => { this.socketIoServer.send('led-strip__changed', ledStrip); }); this.ledController.onBrightnessChanged((brightness) => { this.socketIoServer.send('brightness__changed', brightness); }); } // Route functions loginRequired(_, response) { response.status(200).json({ loginRequired: this.config.useAuth }); } async getLedStrip(_, response) { if (this.currentAnimationProcess) { await new Promise((resolve) => { this.currentAnimationProcess.on('message', (receivedLedStrip) => { response.status(200).json({ ledStrip: receivedLedStrip }); resolve(); }); this.currentAnimationProcess.send({ action: 'get-led-strip' }); }); return; } const ledStrip = this.ledController.getLedStrip(); response.status(200).json({ ledStrip: ledStrip }); } async fillLedStrip(request, response) { const color = request.body.color; const brightness = request.body.brightness; if (!color) { response.status(400).send(`Request body must contain a 'color', e.g. {red: 255, green: 0, blue: 0}.`); return; } this.ledController.fillLeds(color); if (brightness) { this.ledController.setBrightness(brightness); } await this.ledController.show(); const ledStrip = this.ledController.getLedStrip(); this.socketIoServer.send('led-strip-changed', { ledStrip: ledStrip }); response.status(200).json({ ledStrip: ledStrip }); } async clearLedStrip(request, response) { await this.ledController.clearLeds().show(); const ledStrip = this.ledController.getLedStrip(); this.socketIoServer.send('led-strip-changed', { ledStrip: ledStrip }); response.status(200).json({ ledStrip: ledStrip }); } async setSingleLedColor(request, response) { const enteredLedIndex = request.params.ledIndex; const ledIndex = parseInt(enteredLedIndex); const color = request.body.color; const brightness = request.body.brightness; if (Number.isNaN(ledIndex) || ledIndex < 0 || ledIndex >= this.config.amountOfLeds) { response.status(400).send(`URL must contain a led index between 0 and ${this.config.amountOfLeds - 1} (Received ${enteredLedIndex}).`); return; } if (!color) { response.status(400).send(`Request body must contain a 'color', e.g. {red: 255, green: 0, blue: 0}.`); return; } this.ledController.setLed(ledIndex, color); if (brightness) { this.ledController.setBrightness(brightness); } await this.ledController.show(); const ledStrip = this.ledController.getLedStrip(); this.socketIoServer.send('led-strip-changed', { ledStrip: ledStrip }); response.status(200).json({ ledStrip: ledStrip }); } async setBrightness(request, response) { const brightness = request.body.brightness; if (brightness == undefined || (typeof brightness !== 'number' && brightness !== 'auto') || brightness < 0 || brightness > 100) { response.status(400).send(`Request body must contain a 'brightness' (number between 0 and 100 or 'auto' for automatic brightness).`); return; } await this.ledController.setBrightness(brightness).show(); if (this.currentAnimationProcess) { this.currentAnimationProcess.send({ action: 'set-brightness', brightness: brightness }); } this.socketIoServer.send('brightness-changed', { brightness: brightness }); response.status(200).send('success'); } async getBrightness(request, response) { const brightness = this.ledController.getBrightness(); response.status(200).json({ brightness: brightness }); } async setLedStrip(request, response) { const ledStrip = request.body.ledStrip; const brightness = request.body.brightness; if (!ledStrip) { response.status(400).send(`Request body must contain a 'ledStrip' (an array of LedColors with the length of the led strip).`); return; } try { led_strip_validation_1.validateLedStrip(this.ledController.getLedStrip().length, ledStrip); } catch (error) { response.status(400).send(error.message); return; } for (let ledIndex = 0; ledIndex < ledStrip.length; ledIndex++) { this.ledController.setLed(ledIndex, ledStrip[ledIndex]); } if (brightness) { this.ledController.setBrightness(brightness); } await this.ledController.show(); const renderedLedStrip = this.ledController.getLedStrip(); this.socketIoServer.send('led-strip-changed', { ledStrip: renderedLedStrip }); response.status(200).json({ ledStrip: renderedLedStrip }); } async startAnimation(request, response) { const animationScript = request.body.animationScript; if (animationScript == undefined) { response.status(400).send(`Request body must contain a 'animationScript'.`); return; } if (this.currentAnimationProcess) { this.currentAnimationProcess.kill(); this.currentAnimationProcess = undefined; } const brightness = this.ledController.getBrightness(); this.currentAnimationProcess = child_process_1.fork(path_1.default.join(__dirname, 'animator.js'), [this.ledController.getLedStrip().length.toString(), animationScript, brightness.toString()], {}); this.socketIoServer.send('animation__started'); // tslint:disable-next-line: typedef no-any const eventCallback = (message) => { if (message === 'animation-finished') { this.currentAnimationProcess.kill(); this.currentAnimationProcess = undefined; this.socketIoServer.send('animation__finished'); } else if (message.action === 'led-strip-changed') { this.socketIoServer.send('led-strip__changed', message.ledStrip); } }; this.currentAnimationProcess.on('message', eventCallback); response.status(200).send('success!'); } async stopAnimation(request, response) { if (this.currentAnimationProcess) { this.currentAnimationProcess.kill(); this.currentAnimationProcess = undefined; } this.socketIoServer.send('animation__stopped'); response.status(200).send('success!'); } async waitForAnimationToFinish(request, response) { if (!this.currentAnimationProcess) { response.status(200).send('success!'); } // tslint:disable-next-line: typedef no-any this.currentAnimationProcess.on('message', (message) => { if (message === 'animation-finished') { response.status(200).send('success!'); } }); } } exports.Ws2801Webserver = Ws2801Webserver;