From 9f24e6a325fcbddb8c7d431f5bdcc677271d455b Mon Sep 17 00:00:00 2001 From: Maxim Prokhorov Date: Sat, 5 Dec 2020 20:26:40 +0300 Subject: [PATCH] terminal: make sure API is loaded after the web server New apiRegister depends on `webServer()` returning a valid object. --- code/espurna/main.cpp | 6 ++ code/espurna/system.cpp | 2 +- code/espurna/terminal.cpp | 183 ++++++++++++++++++-------------------- code/espurna/terminal.h | 1 + code/espurna/web.cpp | 2 +- 5 files changed, 96 insertions(+), 98 deletions(-) diff --git a/code/espurna/main.cpp b/code/espurna/main.cpp index 2e8ce89a..7d58298d 100644 --- a/code/espurna/main.cpp +++ b/code/espurna/main.cpp @@ -192,6 +192,12 @@ void setup() { apiSetup(); #endif + // Run terminal command and send back the result + #if TERMINAL_WEB_API_SUPPORT + terminalWebApiSetup(); + #endif + + // Special HTTP metrics endpoint #if PROMETHEUS_SUPPORT prometheusSetup(); #endif diff --git a/code/espurna/system.cpp b/code/espurna/system.cpp index 0654f64c..97d9fcf2 100644 --- a/code/espurna/system.cpp +++ b/code/espurna/system.cpp @@ -90,7 +90,7 @@ void systemCheck(bool stable) { if (++value > SYSTEM_CHECK_MAX) { _systemStable = false; - value = 0; + value = SYSTEM_CHECK_MAX; DEBUG_MSG_P(PSTR("[MAIN] System UNSTABLE\n")); } } diff --git a/code/espurna/terminal.cpp b/code/espurna/terminal.cpp index 71bb0db3..7fb7126f 100644 --- a/code/espurna/terminal.cpp +++ b/code/espurna/terminal.cpp @@ -471,96 +471,6 @@ void _terminalLoop() { } -#if TERMINAL_WEB_API_SUPPORT - -void _terminalWebApiSetup() { - -#if API_SUPPORT - - apiRegister(getSetting("termWebApiPath", TERMINAL_WEB_API_PATH), - [](ApiRequest& api) { - api.handle([](AsyncWebServerRequest* request) { - AsyncResponseStream *response = request->beginResponseStream("text/plain"); - for (auto& command : _terminal.commandNames()) { - response->print(command); - response->print("\r\n"); - } - - request->send(response); - }); - return true; - }, - [](ApiRequest& api) { - // TODO: since HTTP spec allows query string to contain repeating keys, allow iteration - // over every 'value' available to provide a way to call multiple commands at once - auto cmd = api.param(F("value")); - if (!cmd.length()) { - return false; - } - - if (!cmd.endsWith("\r\n") && !cmd.endsWith("\n")) { - cmd += '\n'; - } - - api.handle([&](AsyncWebServerRequest* request) { - AsyncWebPrint::scheduleFromRequest(request, [cmd](Print& print) { - StreamAdapter stream(print, cmd.c_str(), cmd.c_str() + cmd.length() + 1); - terminal::Terminal handler(stream); - handler.processLine(); - }); - }); - - return true; - } - ); - -#else - - webRequestRegister([](AsyncWebServerRequest* request) { - String path(F(API_BASE_PATH)); - path += getSetting("termWebApiPath", TERMINAL_WEB_API_PATH); - if (path != request->url()) { - return false; - } - - if (!apiAuthenticate(request)) { - request->send(403); - return true; - } - - auto* cmd_param = request->getParam("value", (request->method() == HTTP_PUT)); - if (!cmd_param) { - request->send(500); - return true; - } - - auto cmd = cmd_param->value(); - if (!cmd.length()) { - request->send(500); - return true; - } - - if (!cmd.endsWith("\r\n") && !cmd.endsWith("\n")) { - cmd += '\n'; - } - - // TODO: batch requests? processLine() -> process(...) - AsyncWebPrint::scheduleFromRequest(request, [cmd](Print& print) { - StreamAdapter stream(print, cmd.c_str(), cmd.c_str() + cmd.length() + 1); - terminal::Terminal handler(stream); - handler.processLine(); - }); - - return true; - }); - -#endif // API_SUPPORT - -} - -#endif // TERMINAL_WEB_API_SUPPORT - - #if MQTT_SUPPORT && TERMINAL_MQTT_SUPPORT void _terminalMqttSetup() { @@ -613,12 +523,98 @@ void _terminalMqttSetup() { #endif // MQTT_SUPPORT && TERMINAL_MQTT_SUPPORT -} +} // namespace // ----------------------------------------------------------------------------- // Pubic API // ----------------------------------------------------------------------------- +#if TERMINAL_WEB_API_SUPPORT + +// XXX: new `apiRegister()` depends that `webServer()` is available, meaning we can't call this setup func +// before the `webSetup()` is called. ATM, just make sure it is in order. + +void terminalWebApiSetup() { +#if API_SUPPORT + apiRegister(getSetting("termWebApiPath", TERMINAL_WEB_API_PATH), + [](ApiRequest& api) { + api.handle([](AsyncWebServerRequest* request) { + AsyncResponseStream *response = request->beginResponseStream("text/plain"); + for (auto* name : _terminal.names()) { + response->print(name); + response->print("\r\n"); + } + + request->send(response); + }); + return true; + }, + [](ApiRequest& api) { + // TODO: since HTTP spec allows query string to contain repeating keys, allow iteration + // over every 'value' available to provide a way to call multiple commands at once + auto cmd = api.param(F("value")); + if (!cmd.length()) { + return false; + } + + if (!cmd.endsWith("\r\n") && !cmd.endsWith("\n")) { + cmd += '\n'; + } + + api.handle([&](AsyncWebServerRequest* request) { + AsyncWebPrint::scheduleFromRequest(request, [cmd](Print& print) { + StreamAdapter stream(print, cmd.c_str(), cmd.c_str() + cmd.length() + 1); + terminal::Terminal handler(stream); + handler.processLine(); + }); + }); + + return true; + } + ); +#else + webRequestRegister([](AsyncWebServerRequest* request) { + String path(F(API_BASE_PATH)); + path += getSetting("termWebApiPath", TERMINAL_WEB_API_PATH); + if (path != request->url()) { + return false; + } + + if (!apiAuthenticate(request)) { + request->send(403); + return true; + } + + auto* cmd_param = request->getParam("value", (request->method() == HTTP_PUT)); + if (!cmd_param) { + request->send(500); + return true; + } + + auto cmd = cmd_param->value(); + if (!cmd.length()) { + request->send(500); + return true; + } + + if (!cmd.endsWith("\r\n") && !cmd.endsWith("\n")) { + cmd += '\n'; + } + + // TODO: batch requests? processLine() -> process(...) + AsyncWebPrint::scheduleFromRequest(request, [cmd](Print& print) { + StreamAdapter stream(print, cmd.c_str(), cmd.c_str() + cmd.length() + 1); + terminal::Terminal handler(stream); + handler.processLine(); + }); + + return true; + }); +#endif // API_SUPPORT +} + +#endif // TERMINAL_WEB_API_SUPPORT + Stream & terminalDefaultStream() { return (Stream &) _io; } @@ -671,11 +667,6 @@ void terminalSetup() { .onVisible([](JsonObject& root) { root["cmdVisible"] = 1; }); #endif - // Run terminal command and send back the result. Depends on the terminal command using ctx.output - #if WEB_SUPPORT && TERMINAL_WEB_API_SUPPORT - _terminalWebApiSetup(); - #endif - // Similar to the above, but we allow only very small and in-place outputs. #if MQTT_SUPPORT && TERMINAL_MQTT_SUPPORT _terminalMqttSetup(); diff --git a/code/espurna/terminal.h b/code/espurna/terminal.h index 048b76c0..161efb6d 100644 --- a/code/espurna/terminal.h +++ b/code/espurna/terminal.h @@ -37,5 +37,6 @@ void terminalInject(char ch); Stream& terminalDefaultStream(); void terminalSetup(); +void terminalWebApiSetup(); #endif // TERMINAL_SUPPORT == 1 diff --git a/code/espurna/web.cpp b/code/espurna/web.cpp index 6fc4dee0..825d5e5a 100644 --- a/code/espurna/web.cpp +++ b/code/espurna/web.cpp @@ -203,7 +203,7 @@ size_t AsyncWebPrint::write(const uint8_t* data, size_t size) { // ----------------------------------------------------------------------------- -AsyncWebServer * _server; +AsyncWebServer* _server; char _last_modified[50]; std::vector * _webConfigBuffer; bool _webConfigSuccess = false;