UNPKG

homebridge-philips-hue-sync-box

Version:
138 lines (125 loc) 4.14 kB
import http from 'http'; import { HueSyncBoxPlatform } from './platform.js'; import { State } from './state.js'; export class ApiServer { private readonly platform: HueSyncBoxPlatform; private server?: http.Server; constructor(platform: HueSyncBoxPlatform) { this.platform = platform; } public start() { const { apiServerPort, apiServerToken } = this.platform.config; if (!apiServerPort || !apiServerToken) { this.platform.log.error( 'API server cannot start due to missing configuration.' ); return; } try { this.server = http .createServer((request, response) => { const payload: unknown[] = []; request .on('error', e => this.platform.log.error( 'API - Error received.', JSON.stringify(e) ) ) .on('data', chunk => payload.push(chunk)) .on('end', async () => { response.on('error', () => this.platform.log.error('API - Error sending the response.') ); if (request.headers['authorization'] !== apiServerToken) { this.platform.log.debug( 'Authorization header missing or invalid.' ); response.statusCode = 401; response.write(JSON.stringify({ error: 'Unauthorized' })); response.end(); return; } switch (request.method) { case 'GET': await this.handleGet(response); break; case 'POST': await this.handlePost(payload, response); break; default: this.platform.log.debug('No action matched.'); response.statusCode = 405; response.end(); } }); }) .listen(apiServerPort, '0.0.0.0'); } catch (e) { this.platform.log.error('API could not be started: ' + JSON.stringify(e)); } this.platform.log.info('API server started.'); } private async handleGet(response: http.ServerResponse) { try { this.platform.log.debug('GET request received.'); const state = await this.platform.client.getState(); response.setHeader('Content-Type', 'application/json'); response.write(JSON.stringify(state)); response.statusCode = 200; } catch (e) { this.platform.log.error('Error while getting the state.', e); response.statusCode = 500; response.write( JSON.stringify({ error: 'An error occurred while processing your request.', }) ); } finally { response.end(); } } private async handlePost(payload: unknown[], response: http.ServerResponse) { if (!payload.length) { response.statusCode = 400; response.write(JSON.stringify({ error: 'Body missing.' })); response.end(); return; } let body: State | null = null; try { body = JSON.parse(Buffer.concat(payload as Uint8Array[]).toString()); if (!body) { // noinspection ExceptionCaughtLocallyJS throw new Error('Body missing.'); } } catch (e) { this.platform.log.error('Body malformed.', e); response.statusCode = 400; response.write(JSON.stringify({ error: 'Body malformed.' })); response.end(); return; } try { if (body.execution) { await this.platform.client.updateExecution(body.execution); } if (body.hue) { await this.platform.client.updateHue(body.hue); } const newState = await this.platform.client.getState(); response.statusCode = 200; response.write(JSON.stringify(newState)); } catch (e) { this.platform.log.error('Error while updating the state.', e); response.statusCode = 500; response.write( JSON.stringify({ error: 'An error occurred while processing your request.', }) ); } finally { response.end(); } } }