188 lines
5.4 KiB
JavaScript
188 lines
5.4 KiB
JavaScript
|
const logger = require('./logger.js');
|
||
|
const hexcolor = require('hex-color-regex');
|
||
|
|
||
|
const LEDS_ALL = require('./blinkstick.js').LEDS_ALL;
|
||
|
const MODE_SET = require('./blinkstick.js').MODE_SET;
|
||
|
const MODE_MORPH = require('./blinkstick.js').MODE_MORPH;
|
||
|
const MODE_BLINK = require('./blinkstick.js').MODE_BLINK;
|
||
|
const MODE_PULSE = require('./blinkstick.js').MODE_PULSE;
|
||
|
const MODE_POWEROFF = require('./blinkstick.js').MODE_POWEROFF;
|
||
|
|
||
|
const DURATION_DEFAULT = require('../config.json').api.post.duration.default || 1000;
|
||
|
const DELAY_DEFAULT = require('../config.json').api.post.delay.default || 500;
|
||
|
|
||
|
const COLOR_RANDOM = 'random';
|
||
|
|
||
|
// parse a http post and return an object with sane defaults
|
||
|
function parseRequest(requestBody, mode) {
|
||
|
if (mode === undefined) {
|
||
|
mode = MODE_SET;
|
||
|
}
|
||
|
let config = {
|
||
|
'id': Math.random(),
|
||
|
'mode': mode,
|
||
|
'options': {
|
||
|
'index': parseIndex(requestBody.index),
|
||
|
}
|
||
|
};
|
||
|
if (config.mode === MODE_POWEROFF) {
|
||
|
config.color = '#000000';
|
||
|
return config;
|
||
|
} else {
|
||
|
config.color = parseColor(requestBody.color);
|
||
|
}
|
||
|
switch (config.mode) {
|
||
|
case MODE_MORPH:
|
||
|
config.options.duration = parseDuration(requestBody.duration, config.options.index);
|
||
|
config.options.steps = parseSteps(requestBody.steps, config.options.duration);
|
||
|
break;
|
||
|
case MODE_BLINK:
|
||
|
config.options.repeats = parseRepeats(requestBody.repeats, config.options.index);
|
||
|
config.repetitions = parseRepetitions(requestBody.repeats, config.options.index);
|
||
|
config.options.delay = parseDelay(requestBody.delay);
|
||
|
break;
|
||
|
case MODE_PULSE:
|
||
|
config.options.duration = parseDuration(requestBody.duration, config.options.index, MODE_PULSE);
|
||
|
config.options.steps = parseSteps(requestBody.steps, config.options.duration);
|
||
|
config.options.repeats = parseRepeats(requestBody.repeats, config.options.index);
|
||
|
config.repetitions = parseRepetitions(requestBody.repeats, config.options.index);
|
||
|
break;
|
||
|
}
|
||
|
return config;
|
||
|
}
|
||
|
|
||
|
// parse the index
|
||
|
function parseIndex(index) {
|
||
|
if (index === undefined) {
|
||
|
return LEDS_ALL;
|
||
|
}
|
||
|
index = parseInt(index);
|
||
|
if (index !== index) {
|
||
|
return LEDS_ALL;
|
||
|
}
|
||
|
if (index < 0) {
|
||
|
index = 0;
|
||
|
} else if (index > 7) {
|
||
|
index = 7;
|
||
|
}
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
// parse the duration
|
||
|
function parseDuration(duration, index, mode) {
|
||
|
if (duration === undefined) {
|
||
|
duration = DURATION_DEFAULT;
|
||
|
}
|
||
|
if (index === LEDS_ALL && mode !== MODE_PULSE) {
|
||
|
duration = duration / 8;
|
||
|
}
|
||
|
if (duration < 100) {
|
||
|
duration = 100;
|
||
|
}
|
||
|
return duration;
|
||
|
}
|
||
|
|
||
|
// parse the steps
|
||
|
function parseSteps(steps, duration) {
|
||
|
if (duration === undefined) {
|
||
|
duration = DURATION_DEFAULT;
|
||
|
}
|
||
|
if (steps === undefined || steps === 0) {
|
||
|
steps = duration / 10;
|
||
|
}
|
||
|
return steps;
|
||
|
}
|
||
|
|
||
|
// parse the repeats
|
||
|
function parseRepeats(repeats, index) {
|
||
|
if (index === LEDS_ALL) {
|
||
|
return 1;
|
||
|
}
|
||
|
repeats = parseInt(repeats);
|
||
|
if (repeats !== repeats) {
|
||
|
return 0;
|
||
|
}
|
||
|
return repeats;
|
||
|
}
|
||
|
|
||
|
// parse the repetitions
|
||
|
function parseRepetitions(repeats, index) {
|
||
|
if (index !== LEDS_ALL) {
|
||
|
return {done: 0, max: 1};
|
||
|
}
|
||
|
repeats = parseInt(repeats);
|
||
|
if (repeats !== repeats) {
|
||
|
repeats = 0;
|
||
|
}
|
||
|
return {done: 0, max: repeats};
|
||
|
}
|
||
|
|
||
|
// parse the delay
|
||
|
function parseDelay(delay) {
|
||
|
if (delay === undefined) {
|
||
|
delay = DELAY_DEFAULT;
|
||
|
}
|
||
|
return delay;
|
||
|
}
|
||
|
|
||
|
// color / parser functions
|
||
|
function parseColor(value) {
|
||
|
if (value === undefined || value === COLOR_RANDOM) {
|
||
|
return COLOR_RANDOM;
|
||
|
}
|
||
|
let parsedColor = parseRGBColor(value);
|
||
|
if (!parsedColor) {
|
||
|
parsedColor = parseHexColor(value);
|
||
|
}
|
||
|
return parsedColor || function () {
|
||
|
logger.warn('could not parse color value \'' + value + '\', defaulting to \'' + COLOR_RANDOM + '\'');
|
||
|
return COLOR_RANDOM;
|
||
|
}();
|
||
|
}
|
||
|
|
||
|
function parseRGBColor(value) {
|
||
|
if (value.indexOf(',') === -1 && isRGBValue(value)) {
|
||
|
return convertRGBToHex(parseInt(value) || 0, 0, 0);
|
||
|
} else {
|
||
|
const splittedValues = value.split(',');
|
||
|
let color = {};
|
||
|
for (let index = 0; index < splittedValues.length; index++) {
|
||
|
const value = splittedValues[index];
|
||
|
if (index === 0) {
|
||
|
color.red = parseInt(value) || 0;
|
||
|
} else if (index === 1) {
|
||
|
color.green = parseInt(value) || 0;
|
||
|
} else if (index === 2) {
|
||
|
color.blue = parseInt(value) || 0;
|
||
|
}
|
||
|
}
|
||
|
if (isRGBValue(color.red) && isRGBValue(color.green) && isRGBValue(color.blue)) {
|
||
|
return convertRGBToHex(color.red, color.green, color.blue);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function isRGBValue(value) {
|
||
|
return value !== undefined && !isNaN(value) && value >= 0 && value <= 255;
|
||
|
}
|
||
|
|
||
|
function convertRGBToHex(red, green, blue) {
|
||
|
return '#' + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1);
|
||
|
}
|
||
|
|
||
|
function parseHexColor(value) {
|
||
|
if (value[0] !== '#') {
|
||
|
value = '#' + value;
|
||
|
}
|
||
|
if (value.length === 4) {
|
||
|
value = (value[0] + value[1] + value[1] + value[2] + value[2] + value[3] + value[3]);
|
||
|
}
|
||
|
if (hexcolor({strict: true}).test(value)) {
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// exports
|
||
|
module.exports = {
|
||
|
parseRequest,
|
||
|
};
|