homebridge-philips-hue-sync-box
Version:
Homebridge plugin for the Philips Hue Sync Box.
138 lines (125 loc) • 4.14 kB
text/typescript
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();
}
}
}