mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Json write (#313)
* always output latest version of config file to webui * fix permissions after default config export * tune code * set permissions for exported effects * use qt setperm instead of chmod update effects code style a bit * add fallback when config is not readable * ui: when sending config, convert to utf8 to save size and avoid jumbo frames (todo: minify it) jsonclient: add some constants for websocket frames (taken from https://github.com/zaphoyd/websocketpp/blob/master/websocketpp/frame.hpp) * webui: refactory of websocket connector sended json data is always convert to utf8
This commit is contained in:
parent
8d55154164
commit
9428586195
@ -116,7 +116,20 @@ function initWebSocket()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendToHyperion(command, subcommand, msg)
|
||||||
|
{
|
||||||
|
if (typeof subcommand != 'undefined' && subcommand.length > 0)
|
||||||
|
subcommand = ',"subcommand":"'+subcommand+'"';
|
||||||
|
else
|
||||||
|
subcommand = "";
|
||||||
|
|
||||||
|
if (typeof msg != 'undefined' && msg.length > 0)
|
||||||
|
msg = ","+msg;
|
||||||
|
else
|
||||||
|
msg = "";
|
||||||
|
|
||||||
|
websocket.send(encode_utf8('{"command":"'+command+'", "tan":'+wsTan+subcommand+msg+'}'));
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------
|
// -----------------------------------------------------------
|
||||||
// wrapped server commands
|
// wrapped server commands
|
||||||
@ -124,55 +137,55 @@ function initWebSocket()
|
|||||||
// also used for watchdog
|
// also used for watchdog
|
||||||
function requestServerInfo() {
|
function requestServerInfo() {
|
||||||
watchdog++;
|
watchdog++;
|
||||||
websocket.send('{"command":"serverinfo", "tan":'+wsTan+'}');
|
sendToHyperion("serverinfo");
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestServerConfigSchema() {
|
function requestServerConfigSchema() {
|
||||||
websocket.send('{"command":"config", "tan":'+wsTan+',"subcommand":"getschema"}');
|
sendToHyperion("config","getschema");
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestServerConfig() {
|
function requestServerConfig() {
|
||||||
websocket.send('{"command":"config", "tan":'+wsTan+',"subcommand":"getconfig"}');
|
sendToHyperion("config", "getconfig");
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestServerConfigReload() {
|
function requestServerConfigReload() {
|
||||||
websocket.send('{"command":"config", "tan":'+wsTan+',"subcommand":"reload"}');
|
sendToHyperion("config", "reload");
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestLedColorsStart() {
|
function requestLedColorsStart() {
|
||||||
ledStreamActive=true;
|
ledStreamActive=true;
|
||||||
websocket.send('{"command":"ledcolors", "tan":'+wsTan+',"subcommand":"ledstream-start"}');
|
sendToHyperion("ledcolors", "ledstream-start");
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestLedColorsStop() {
|
function requestLedColorsStop() {
|
||||||
ledStreamActive=false;
|
ledStreamActive=false;
|
||||||
websocket.send('{"command":"ledcolors", "tan":'+wsTan+',"subcommand":"ledstream-stop"}');
|
sendToHyperion("ledcolors", "ledstream-stop");
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestPriorityClear() {
|
function requestPriorityClear() {
|
||||||
websocket.send('{"command":"clear", "tan":'+wsTan+', "priority":1}');
|
sendToHyperion("clear", "", '"priority":1');
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestPlayEffect(effectName) {
|
function requestPlayEffect(effectName) {
|
||||||
websocket.send('{"command":"effect", "tan":'+wsTan+',"effect":{"name":"'+effectName+'"},"priority":1}');
|
sendToHyperion("effect", "", '"effect":{"name":"'+effectName+'"},"priority":1');
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestSetColor(r,g,b) {
|
function requestSetColor(r,g,b) {
|
||||||
websocket.send('{"command":"color", "tan":'+wsTan+', "color":['+r+','+g+','+b+'], "priority":1}');
|
sendToHyperion("color", "", '"color":['+r+','+g+','+b+'], "priority":1');
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestSetComponentState(comp, state){
|
function requestSetComponentState(comp, state){
|
||||||
state_str = state?"true":"false";
|
state_str = state ? "true" : "false";
|
||||||
websocket.send('{"command":"componentstate", "tan":'+wsTan+',"componentstate":{"component":"'+comp+'","state":'+state_str+'}}');
|
sendToHyperion("componentstate", "", '"componentstate":{"component":"'+comp+'","state":'+state_str+'}');
|
||||||
console.log(comp+' state: '+state_str);
|
console.log(comp+' state: '+state_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestSetSource(prio)
|
function requestSetSource(prio)
|
||||||
{
|
{
|
||||||
if ( prio == "auto" )
|
if ( prio == "auto" )
|
||||||
websocket.send('{"command":"sourceselect", "tan":'+wsTan+', "auto" : true}');
|
sendToHyperion("sourceselect", "", '"auto":true');
|
||||||
else
|
else
|
||||||
websocket.send('{"command":"sourceselect", "tan":'+wsTan+', "priority" : '+prio+'}');
|
sendToHyperion("sourceselect", "", '"priority":'+prio);
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestWriteConfig(config)
|
function requestWriteConfig(config)
|
||||||
@ -181,30 +194,36 @@ function requestWriteConfig(config)
|
|||||||
jQuery.each(config, function(i, val) {
|
jQuery.each(config, function(i, val) {
|
||||||
complete_config[i] = val;
|
complete_config[i] = val;
|
||||||
});
|
});
|
||||||
websocket.send('{"command":"config","subcommand":"setconfig", "tan":'+wsTan+', "config":'+JSON.stringify(complete_config)+'}');
|
|
||||||
|
var config_str = JSON.stringify(complete_config);
|
||||||
|
console.log(config_str.length);
|
||||||
|
sendToHyperion("config","setconfig", '"config":'+config_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestWriteEffect(effectName,effectPy,effectArgs)
|
function requestWriteEffect(effectName,effectPy,effectArgs)
|
||||||
{
|
{
|
||||||
var cutArgs = effectArgs.slice(1, -1);
|
var cutArgs = effectArgs.slice(1, -1);
|
||||||
websocket.send('{"command":"create-effect","name":"'+effectName+'", "script":"'+effectPy+'", '+cutArgs+'}');
|
sendToHyperion("create-effect", "", '"name":"'+effectName+'", "script":"'+effectPy+'", '+cutArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestTestEffect(effectName,effectPy,effectArgs) {
|
function requestTestEffect(effectName,effectPy,effectArgs) {
|
||||||
websocket.send('{"command":"effect", "tan":'+wsTan+',"effect":{"name":"'+effectName+'", "args":'+effectArgs+'},"priority":1, "pythonScript":"'+effectPy+'"}');
|
sendToHyperion("effect", "", '"effect":{"name":"'+effectName+'", "args":'+effectArgs+'},"priority":1, "pythonScript":"'+effectPy+'"}');
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestDeleteEffect(effectName) {
|
function requestDeleteEffect(effectName)
|
||||||
websocket.send('{"command":"delete-effect", "tan":'+wsTan+',"name":"'+effectName+'"}');
|
{
|
||||||
|
sendToHyperion("delete-effect", "", '"name":"'+effectName+'"');
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestLoggingStart() {
|
function requestLoggingStart()
|
||||||
|
{
|
||||||
loggingStreamActive=true;
|
loggingStreamActive=true;
|
||||||
websocket.send('{"command":"logging", "tan":'+wsTan+',"subcommand":"start"}');
|
sendToHyperion("logging", "start");
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestLoggingStop() {
|
function requestLoggingStop()
|
||||||
|
{
|
||||||
loggingStreamActive=false;
|
loggingStreamActive=false;
|
||||||
websocket.send('{"command":"logging", "tan":'+wsTan+',"subcommand":"stop"}');
|
sendToHyperion("logging", "stop");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,23 +120,28 @@ function createJsonEditor(container,schema,setconfig)
|
|||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSelGroup(group){
|
function createSelGroup(group)
|
||||||
|
{
|
||||||
var el = document.createElement('optgroup');
|
var el = document.createElement('optgroup');
|
||||||
el.setAttribute('label', group);
|
el.setAttribute('label', group);
|
||||||
return el
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSelOpt(opt){
|
function createSelOpt(opt)
|
||||||
|
{
|
||||||
var el = document.createElement('option');
|
var el = document.createElement('option');
|
||||||
el.setAttribute('value', opt);
|
el.setAttribute('value', opt);
|
||||||
el.innerHTML = opt;
|
el.innerHTML = opt;
|
||||||
return el
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSel(array, group){
|
function createSel(array, group)
|
||||||
if (array.length != "0"){
|
{
|
||||||
|
if (array.length != "0")
|
||||||
|
{
|
||||||
var el = createSelGroup(group);
|
var el = createSelGroup(group);
|
||||||
for(var i=0; i<array.length; i++){
|
for(var i=0; i<array.length; i++)
|
||||||
|
{
|
||||||
var opt = createSelOpt(array[i])
|
var opt = createSelOpt(array[i])
|
||||||
el.appendChild(opt);
|
el.appendChild(opt);
|
||||||
}
|
}
|
||||||
@ -144,6 +149,12 @@ function createSel(array, group){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function performTranslation(){
|
function performTranslation()
|
||||||
|
{
|
||||||
$('#wrapper').i18n();
|
$('#wrapper').i18n();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function encode_utf8(s)
|
||||||
|
{
|
||||||
|
return unescape(encodeURIComponent(s));
|
||||||
|
}
|
||||||
|
@ -74,7 +74,8 @@ void JsonClientConnection::readData()
|
|||||||
{
|
{
|
||||||
// websocket mode, data frame
|
// websocket mode, data frame
|
||||||
handleWebSocketFrame();
|
handleWebSocketFrame();
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// might be a handshake request or raw socket data
|
// might be a handshake request or raw socket data
|
||||||
if(_receiveBuffer.contains("Upgrade: websocket"))
|
if(_receiveBuffer.contains("Upgrade: websocket"))
|
||||||
@ -104,24 +105,25 @@ void JsonClientConnection::readData()
|
|||||||
|
|
||||||
void JsonClientConnection::handleWebSocketFrame()
|
void JsonClientConnection::handleWebSocketFrame()
|
||||||
{
|
{
|
||||||
if ((_receiveBuffer.at(0) & 0x80) == 0x80)
|
if ((_receiveBuffer.at(0) & BHB0_FIN) == BHB0_FIN)
|
||||||
{
|
{
|
||||||
// final bit found, frame complete
|
// final bit found, frame complete
|
||||||
quint8 * maskKey = NULL;
|
quint8 * maskKey = NULL;
|
||||||
quint8 opCode = _receiveBuffer.at(0) & 0x0F;
|
quint8 opCode = _receiveBuffer.at(0) & BHB0_OPCODE;
|
||||||
bool isMasked = (_receiveBuffer.at(1) & 0x80) == 0x80;
|
bool isMasked = (_receiveBuffer.at(1) & BHB0_FIN) == BHB0_FIN;
|
||||||
quint64 payloadLength = _receiveBuffer.at(1) & 0x7F;
|
quint64 payloadLength = _receiveBuffer.at(1) & BHB1_PAYLOAD;
|
||||||
quint32 index = 2;
|
quint32 index = 2;
|
||||||
|
|
||||||
switch (payloadLength)
|
switch (payloadLength)
|
||||||
{
|
{
|
||||||
case 126:
|
case payload_size_code_16bit:
|
||||||
payloadLength = ((_receiveBuffer.at(2) << 8) & 0xFF00) | (_receiveBuffer.at(3) & 0xFF);
|
payloadLength = ((_receiveBuffer.at(2) << 8) & 0xFF00) | (_receiveBuffer.at(3) & 0xFF);
|
||||||
index += 2;
|
index += 2;
|
||||||
break;
|
break;
|
||||||
case 127:
|
case payload_size_code_64bit:
|
||||||
payloadLength = 0;
|
payloadLength = 0;
|
||||||
for (uint i=0; i < 8; i++) {
|
for (uint i=0; i < 8; i++)
|
||||||
|
{
|
||||||
payloadLength |= ((quint64)(_receiveBuffer.at(index+i) & 0xFF)) << (8*(7-i));
|
payloadLength |= ((quint64)(_receiveBuffer.at(index+i) & 0xFF)) << (8*(7-i));
|
||||||
}
|
}
|
||||||
index += 8;
|
index += 8;
|
||||||
@ -144,7 +146,7 @@ void JsonClientConnection::handleWebSocketFrame()
|
|||||||
// check the type of data frame
|
// check the type of data frame
|
||||||
switch (opCode)
|
switch (opCode)
|
||||||
{
|
{
|
||||||
case 0x01:
|
case OPCODE::TEXT:
|
||||||
{
|
{
|
||||||
// frame contains text, extract it
|
// frame contains text, extract it
|
||||||
QByteArray result = _receiveBuffer.mid(index, payloadLength);
|
QByteArray result = _receiveBuffer.mid(index, payloadLength);
|
||||||
@ -167,7 +169,7 @@ void JsonClientConnection::handleWebSocketFrame()
|
|||||||
handleMessage(QString(result));
|
handleMessage(QString(result));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x08:
|
case OPCODE::CLOSE:
|
||||||
{
|
{
|
||||||
// close request, confirm
|
// close request, confirm
|
||||||
quint8 close[] = {0x88, 0};
|
quint8 close[] = {0x88, 0};
|
||||||
@ -176,16 +178,17 @@ void JsonClientConnection::handleWebSocketFrame()
|
|||||||
_socket->close();
|
_socket->close();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x09:
|
case OPCODE::PING:
|
||||||
{
|
{
|
||||||
// ping received, send pong
|
// ping received, send pong
|
||||||
quint8 pong[] = {0x0A, 0};
|
quint8 pong[] = {OPCODE::PONG, 0};
|
||||||
_socket->write((const char*)pong, 2);
|
_socket->write((const char*)pong, 2);
|
||||||
_socket->flush();
|
_socket->flush();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Error(_log, "Someone is sending very big messages over several frames... it's not supported yet");
|
Error(_log, "Someone is sending very big messages over several frames... it's not supported yet");
|
||||||
quint8 close[] = {0x88, 0};
|
quint8 close[] = {0x88, 0};
|
||||||
|
@ -17,6 +17,63 @@
|
|||||||
|
|
||||||
class ImageProcessor;
|
class ImageProcessor;
|
||||||
|
|
||||||
|
|
||||||
|
/// Constants and utility functions related to WebSocket opcodes
|
||||||
|
/**
|
||||||
|
* WebSocket Opcodes are 4 bits. See RFC6455 section 5.2.
|
||||||
|
*/
|
||||||
|
namespace OPCODE {
|
||||||
|
enum value {
|
||||||
|
CONTINUATION = 0x0,
|
||||||
|
TEXT = 0x1,
|
||||||
|
BINARY = 0x2,
|
||||||
|
RSV3 = 0x3,
|
||||||
|
RSV4 = 0x4,
|
||||||
|
RSV5 = 0x5,
|
||||||
|
RSV6 = 0x6,
|
||||||
|
RSV7 = 0x7,
|
||||||
|
CLOSE = 0x8,
|
||||||
|
PING = 0x9,
|
||||||
|
PONG = 0xA,
|
||||||
|
CONTROL_RSVB = 0xB,
|
||||||
|
CONTROL_RSVC = 0xC,
|
||||||
|
CONTROL_RSVD = 0xD,
|
||||||
|
CONTROL_RSVE = 0xE,
|
||||||
|
CONTROL_RSVF = 0xF
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Check if an opcode is reserved
|
||||||
|
/**
|
||||||
|
* @param v The opcode to test.
|
||||||
|
* @return Whether or not the opcode is reserved.
|
||||||
|
*/
|
||||||
|
inline bool reserved(value v) {
|
||||||
|
return (v >= RSV3 && v <= RSV7) || (v >= CONTROL_RSVB && v <= CONTROL_RSVF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if an opcode is invalid
|
||||||
|
/**
|
||||||
|
* Invalid opcodes are negative or require greater than 4 bits to store.
|
||||||
|
*
|
||||||
|
* @param v The opcode to test.
|
||||||
|
* @return Whether or not the opcode is invalid.
|
||||||
|
*/
|
||||||
|
inline bool invalid(value v) {
|
||||||
|
return (v > 0xF || v < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if an opcode is for a control frame
|
||||||
|
/**
|
||||||
|
* @param v The opcode to test.
|
||||||
|
* @return Whether or not the opcode is a control opcode.
|
||||||
|
*/
|
||||||
|
inline bool is_control(value v) {
|
||||||
|
return v >= 0x8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The Connection object created by \a JsonServer when a new connection is establshed
|
/// The Connection object created by \a JsonServer when a new connection is establshed
|
||||||
///
|
///
|
||||||
@ -228,7 +285,6 @@ private:
|
|||||||
///
|
///
|
||||||
void forwardJsonMessage(const QJsonObject & message);
|
void forwardJsonMessage(const QJsonObject & message);
|
||||||
|
|
||||||
private:
|
|
||||||
///
|
///
|
||||||
/// Check if a JSON messag is valid according to a given JSON schema
|
/// Check if a JSON messag is valid according to a given JSON schema
|
||||||
///
|
///
|
||||||
@ -270,4 +326,16 @@ private:
|
|||||||
QJsonObject _streaming_logging_reply;
|
QJsonObject _streaming_logging_reply;
|
||||||
bool _streaming_logging_activated;
|
bool _streaming_logging_activated;
|
||||||
|
|
||||||
|
// masks for fields in the basic header
|
||||||
|
static uint8_t const BHB0_OPCODE = 0x0F;
|
||||||
|
static uint8_t const BHB0_RSV3 = 0x10;
|
||||||
|
static uint8_t const BHB0_RSV2 = 0x20;
|
||||||
|
static uint8_t const BHB0_RSV1 = 0x40;
|
||||||
|
static uint8_t const BHB0_FIN = 0x80;
|
||||||
|
|
||||||
|
static uint8_t const BHB1_PAYLOAD = 0x7F;
|
||||||
|
static uint8_t const BHB1_MASK = 0x80;
|
||||||
|
|
||||||
|
static uint8_t const payload_size_code_16bit = 0x7E; // 126
|
||||||
|
static uint8_t const payload_size_code_64bit = 0x7F; // 127
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user