system config UI work in progress

This commit is contained in:
Sebastien
2020-04-29 19:38:00 -04:00
parent 396f4e58de
commit 293d08deec
29 changed files with 682 additions and 240 deletions

View File

@@ -32,6 +32,20 @@ var task_state_t = {
4 : "eDeleted"
}
var escapeHTML = function(unsafe) {
return unsafe.replace(/[&<"']/g, function(m) {
switch (m) {
case '&':
return '&amp;';
case '<':
return '&lt;';
case '"':
return '&quot;';
default:
return '&#039;';
}
});
};
var releaseURL = 'https://api.github.com/repos/sle118/squeezelite-esp32/releases';
var recovery = false;
var enableAPTimer = true;
@@ -737,7 +751,7 @@ function getMessages() {
$("#syslogTable").append(
"<tr class='"+msg["type"]+"'>"+
"<td>"+msg_time.toLocaleString()+"</td>"+
"<td>"+msg["message"]+"</td>"+
"<td>"+escapeHTML(msg["message"]).replace(/\n/g, '<br />')+"</td>"+
"</tr>"
);
break;
@@ -921,15 +935,124 @@ function checkStatus(){
blockAjax = false;
});
}
function runCommand(button) {
pardiv = button.parentNode.parentNode;
fields=document.getElementById("flds-"+button.value);
cmdstring=button.value+' ';
if(fields){
hint = pardiv.hint;
allfields=fields.getElementsByTagName("input");
for (i = 0; i < allfields.length; i++) {
attr=allfields[i].attributes;
qts='';
opt='';
optspacer=' ';
if (attr.longopts.value!== "undefined"){
opt+= '--' + attr.longopts.value;
optspacer='=';
}
else if(attr.shortopts.value!== "undefined"){
opt= '-' + attr.shortopts.value;
}
if(attr.hasvalue.value== "true" ){
if(allfields[i].value!=''){
qts = (/\s/.test(allfields[i].value))?'"':'';
cmdstring+=opt+optspacer+qts +allfields[i].value +qts+ ' ';
}
}
else {
// this is a checkbox
if(allfields[i].checked) cmdstring+=opt+ ' ';
}
}
}
console.log(cmdstring);
var data = { 'timestamp': Date.now() };
data['command'] = cmdstring;
$.ajax({
url: '/commands.json',
dataType: 'text',
method: 'POST',
cache: false,
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(data),
error: function (xhr, ajaxOptions, thrownError) {
console.log(xhr.status);
console.log(thrownError);
if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR');
}
});
enableStatusTimer = true;
}
function getCommands() {
$.getJSON("/commands.json", function(data) {
console.log(data);
innerhtml='';
data.commands.forEach(function(command) {
innerhtml+='<tr><td>';
innerhtml+=escapeHTML(command.help).replace(/\n/g, '<br />')+'<br>';
innerhtml+='<div >';
if(command.hasOwnProperty("argtable")){
innerhtml+='<table class="table table-hover" id="flds-'+command.name+'"><tbody>';
command.argtable.forEach(function (arg){
innerhtml+="<tr>";
ctrlname=command.name+'-'+arg.longopts;
innerhtml+='<td><label for="'+ctrlname+'">'+ arg.glossary+'</label></td>';
ctrltype="text";
if(arg.checkbox){
ctrltype="checkbox";
}
curvalue=data.values?.[command.name]?.[arg.longopts] || '';
placeholder=arg?.datatype || '';
innerhtml+='<td><input type="'+ctrltype+'" id="'+ctrlname+'" name="'+ctrlname+'" placeholder="'+placeholder+'" hasvalue="'+arg.hasvalue+'" ';
innerhtml+='datatype="'+arg.datatype+'" ';
innerhtml+='hasvalue='+arg.hasvalue+' ';
innerhtml+='longopts="'+arg.longopts+'" ';
innerhtml+='shortopts="'+arg.shortopts+'" ';
innerhtml+='checkbox='+arg.checkbox+' ';
if(arg.checkbox){
if(curvalue=data.values?.[command.name]?.[arg.longopts] ){
innerhtml+='checked=true ';
}
else{
innerhtml+='checked=false ';
}
innerhtml+='></input></td>';
}
else {
innerhtml+='value="'+curvalue+'" ';
innerhtml+='></input></td>'+ curvalue.length>0?'<td>last: '+curvalue+'</td>':'';
}
innerhtml+="</tr>";
});
innerhtml+='</tbody></table><br>';
}
innerhtml+='<div class="buttons"><input id="btn-'+ command.name + '" type="button" class="btn btn-danger btn-sm" value="'+command.name+'" onclick="runCommand(this);"></div></div><td></tr>';
});
$("#commands-list").append(innerhtml);
})
.fail(function(xhr, ajaxOptions, thrownError) {
console.log(xhr.status);
console.log(thrownError);
$("#commands-list").empty();
if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR');
blockAjax = false;
});

View File

@@ -80,7 +80,7 @@ union sockaddr_aligned {
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} aligned_sockaddr_t;
esp_err_t post_handler_buff_receive(httpd_req_t * req);
static const char redirect_payload1[]="<html><head><title>Redirecting to Captive Portal</title><meta http-equiv='refresh' content='0; url=";
static const char redirect_payload2[]="'></head><body><p>Please wait, refreshing. If page does not refresh, click <a href='";
static const char redirect_payload3[]="'>here</a> to login.</p></body></html>";
@@ -483,6 +483,54 @@ esp_err_t console_cmd_get_handler(httpd_req_t *req){
ESP_LOGD_LOC(TAG, "Error retrieving command json string. ");
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to format command");
}
cJSON_free(cmdlist);
ESP_LOGD_LOC(TAG, "done serving [%s]", req->uri);
return err;
}
esp_err_t console_cmd_post_handler(httpd_req_t *req){
char success[]="{}";
ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
bool bOTA=false;
char * otaURL=NULL;
esp_err_t err = post_handler_buff_receive(req);
if(err!=ESP_OK){
return err;
}
if(!is_user_authenticated(req)){
// todo: redirect to login page
// return ESP_OK;
}
err = set_content_type_from_req(req);
if(err != ESP_OK){
return err;
}
char *command= ((rest_server_context_t *)(req->user_ctx))->scratch;
cJSON *root = cJSON_Parse(command);
if(root == NULL){
ESP_LOGE_LOC(TAG, "Parsing command. Received content was: %s",command);
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed command json. Unable to parse content.");
return ESP_FAIL;
}
char * root_str = cJSON_Print(root);
if(root_str!=NULL){
ESP_LOGD(TAG, "Processing command item: \n%s", root_str);
free(root_str);
}
cJSON *item=cJSON_GetObjectItemCaseSensitive(root, "command");
if(!item){
ESP_LOGE_LOC(TAG, "Command not found. Received content was: %s",command);
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed command json. Unable to parse content.");
err = ESP_FAIL;
}
else{
// navigate to the first child of the config structure
run_command(cJSON_GetStringValue(item));
}
httpd_resp_send(req, (const char *)success, strlen(success));
ESP_LOGD_LOC(TAG, "done serving [%s]", req->uri);
return err;
}

View File

@@ -92,6 +92,7 @@ esp_err_t flash_post_handler(httpd_req_t *req);
esp_err_t status_get_handler(httpd_req_t *req);
esp_err_t messages_get_handler(httpd_req_t *req);
esp_err_t console_cmd_get_handler(httpd_req_t *req);
esp_err_t console_cmd_post_handler(httpd_req_t *req);
esp_err_t ap_scan_handler(httpd_req_t *req);
esp_err_t redirect_ev_handler(httpd_req_t *req);
esp_err_t redirect_200_ev_handler(httpd_req_t *req);

View File

@@ -70,6 +70,9 @@
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#tab-syslog">Syslog</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#tab-commands">System</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#tab-nvs">NVS editor</a>
</li>
@@ -295,6 +298,12 @@
</div>
</div>
</div> <!-- firmware -->
<div class="tab-pane fade" id="tab-commands">
<table class="table table-hover" id="commands-list-table">
<tbody id="commands-list">
</tbody>
</table>
</div> <!-- system -->
<div class="tab-pane fade" id="tab-syslog">
<table class="table table-hover">

View File

@@ -60,6 +60,8 @@ void register_regular_handlers(httpd_handle_t server){
httpd_uri_t commands_get = { .uri = "/commands.json", .method = HTTP_GET, .handler = console_cmd_get_handler, .user_ctx = rest_context };
httpd_register_uri_handler(server, &commands_get);
httpd_uri_t commands_post = { .uri = "/commands.json", .method = HTTP_POST, .handler = console_cmd_post_handler, .user_ctx = rest_context };
httpd_register_uri_handler(server, &commands_post);
httpd_uri_t config_post = { .uri = "/config.json", .method = HTTP_POST, .handler = config_post_handler, .user_ctx = rest_context };
httpd_register_uri_handler(server, &config_post);