diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 660176b..4b96d1a 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -100,6 +100,7 @@ set(headers displays/menus/presetsmenu.h displays/menus/profilesmenu.h displays/menus/selectbatterytypemenu.h + displays/menus/selectbuildserverbranch.h displays/menus/selectbuildservermenu.h displays/menus/selectmodemenu.h displays/menus/selectotabuildmenu.h @@ -297,6 +298,7 @@ set(sources displays/menus/presetsmenu.cpp displays/menus/profilesmenu.cpp displays/menus/selectbatterytypemenu.cpp + displays/menus/selectbuildserverbranch.cpp displays/menus/selectbuildservermenu.cpp displays/menus/selectmodemenu.cpp displays/menus/selectotabuildmenu.cpp diff --git a/main/buildserver.cpp b/main/buildserver.cpp index af3ea46..e5d8734 100644 --- a/main/buildserver.cpp +++ b/main/buildserver.cpp @@ -18,7 +18,111 @@ #include "esp_http_client.h" #ifdef FEATURE_OTA + namespace buildserver { + + uint16_t count_available_buildserver() + { + uint16_t count = 0; + for (const auto &otaServer : stringSettings.otaServers) { + if (!otaServer.url.empty()) count++; + } + return count; + } + + namespace SelectBranch { + cpputils::DelayedConstruction request; + bool request_running{false}; + bool constructedMenu{false}; + std::string request_failed{}; + std::vector branches{}; + + void setup_request() + { + if (!request.constructed()) + { + request.construct("ota-descriptor-request", espcpputils::CoreAffinity::Core0); + } + } + + void start_descriptor_request(std::string server_base_url) + { + if (!request.constructed()) + { + ESP_LOGW("BOBBY", "request is im oarsch"); + return; + } + + const auto url = fmt::format("{}/otaDescriptor?username={}&branches", server_base_url, OTA_USERNAME); + ESP_LOGD("BOBBY", "requesting data..."); + if (const auto result = request->start(url); !result) + { + ESP_LOGW("BOBBY", "request start failed"); + return; + } + request_running = true; + constructedMenu = false; + } + + + void check_descriptor_request() + { + if (!request.constructed()) + { + ESP_LOGW("BOBBY", "request is im oarsch"); + request_running = false; + request_failed = "request is im oarsch"; + return; + } + + if (!request->finished()) + { + // ESP_LOGW("BOBBY", "Request has not finished yet."); + return; + } + + const auto helper = cpputils::makeCleanupHelper([](){ request->clearFinished(); }); + const std::string content = std::move(request->takeBuffer()); + + if (const auto result = request->result(); !result) + { + ESP_LOGW("BOBBY", "request failed: %.*s", result.error().size(), result.error().data()); + request_failed = result.error(); + return; + } + + const auto result = request->result(); + ESP_LOGW("BOBBY", "Request finished: %s", content.c_str()); + parse_response(content); + request_running = false; + request_failed = {}; + } + + void parse_response(std::string response) + { + StaticJsonDocument<1024> doc; + + if (const auto error = deserializeJson(doc, response)) + { + ESP_LOGE("BOBBY", "Error parsing server-response => %s (%s)", error.c_str(), response.c_str()); + return; + } + + JsonArray arr = doc.as(); + branches.resize(arr.size()); + + for(JsonVariant v : arr) { + branches.push_back(v); + } + } + + bool get_request_running() + { + return request_running; + } + } // namespace SelectBranch + + namespace SelectBuild { void buildMenuFromJson(std::string json); void buildMenuRequestError(std::string error); @@ -27,7 +131,7 @@ namespace buildserver { std::array availableVersions{}; bool request_running{false}; std::string request_failed{}; - bool parsing_finished{true}; + bool parsing_finished{false}; cpputils::DelayedConstruction request; std::string get_ota_url_from_index(uint16_t index) @@ -52,15 +156,6 @@ namespace buildserver { } } - uint16_t count_available_buildserver() - { - uint16_t count = 0; - for (const auto &otaServer : stringSettings.otaServers) { - if (!otaServer.url.empty()) count++; - } - return count; - } - std::string get_hash_url(std::string hash) { return fmt::format(url_for_hashes, hash); @@ -73,7 +168,10 @@ namespace buildserver { std::string get_descriptor_url(std::string base_url) { - return fmt::format("{}/otaDescriptor?username={}", base_url, OTA_USERNAME); + if (stringSettings.otaServerBranch.empty()) + return fmt::format("{}/otaDescriptor?username={}", base_url, OTA_USERNAME); + else + return fmt::format("{}/otaDescriptor?username={}&branch={}", base_url, OTA_USERNAME, stringSettings.otaServerBranch); } void parse_response_into_variables(std::string response) @@ -172,5 +270,6 @@ namespace buildserver { { return request_running; } -} + } // namespace SelectBuild +} // namespace buildserver #endif diff --git a/main/buildserver.h b/main/buildserver.h index 0ce3d3c..99eb6d8 100644 --- a/main/buildserver.h +++ b/main/buildserver.h @@ -8,6 +8,24 @@ #ifdef FEATURE_OTA namespace buildserver { + +uint16_t count_available_buildserver(); + +namespace SelectBranch { + extern cpputils::DelayedConstruction request; + extern bool request_running; + extern bool constructedMenu; + void setup_request(); + void start_descriptor_request(std::string server_base_url); + void check_descriptor_request(); + void parse_response(std::string response); + bool get_request_running(); + extern std::string request_failed; + extern std::vector branches; +} // namespace SelectBranch + +namespace SelectBuild { + void buildMenuFromJson(std::string json); void buildMenuRequestError(std::string error); @@ -20,7 +38,6 @@ namespace buildserver { extern cpputils::DelayedConstruction request; std::string get_ota_url_from_index(uint16_t index); - uint16_t count_available_buildserver(); std::string get_hash_url(std::string hash); std::string get_latest_url(); std::string get_descriptor_url(std::string base_url); @@ -29,5 +46,6 @@ namespace buildserver { void start_descriptor_request(std::string server_base_url); void check_descriptor_request(); bool get_request_running(); -} +} // namespace SelectBuild +} // namespace buildserver #endif diff --git a/main/displays/menus/otamenu.cpp b/main/displays/menus/otamenu.cpp index 4ccfde0..f28f478 100644 --- a/main/displays/menus/otamenu.cpp +++ b/main/displays/menus/otamenu.cpp @@ -10,6 +10,7 @@ #include "icons/presets.h" #include "icons/update.h" #include "displays/menus/selectotabuildmenu.h" +#include "displays/menus/selectbuildserverbranch.h" #include "displays/menus/selectbuildservermenu.h" #include "displays/menus/mainmenu.h" #include "displays/updatedisplay.h" @@ -21,6 +22,7 @@ using namespace espgui; OtaMenu::OtaMenu() { constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&bobbyicons::presets>>>(); + constructMenuItem, SwitchScreenAction>>(); constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&bobbyicons::update>>>(); constructMenuItem, SwitchScreenAction>>(); constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>(); diff --git a/main/displays/menus/selectbuildserverbranch.cpp b/main/displays/menus/selectbuildserverbranch.cpp new file mode 100644 index 0000000..eaf846c --- /dev/null +++ b/main/displays/menus/selectbuildserverbranch.cpp @@ -0,0 +1,128 @@ +#ifdef FEATURE_OTA +#include "selectbuildserverbranch.h" + +// 3rd party includes +#include + +// local includes +#include "actions/dummyaction.h" +#include "actions/switchscreenaction.h" +#include "buildserver.h" +#include "displays/menus/otamenu.h" +#include "globals.h" +#include "icons/back.h" +#include "icons/reboot.h" +#include "utils.h" + +#define ERR_MESSAGE(text) \ + constructMenuItem, DefaultFont, StaticColor, DummyAction>>(); \ + constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>(); \ + return; + +using namespace espgui; +using namespace buildserver; +using namespace SelectBuildServerBranch; + +namespace SelectBuildServerBranch { +std::string CurrentBranch::text() const +{ + return stringSettings.otaServerBranch.empty() ? "All builds" : stringSettings.otaServerBranch; +} + +std::string BranchMenuItem::text() const +{ + return m_name; +} + +void BranchMenuItem::setName(std::string &&name) +{ + m_name = std::move(name); +} + +void BranchMenuItem::setName(const std::string &name) +{ + m_name = name; +} + +void BranchMenuItem::triggered() +{ + stringSettings.otaServerBranch = m_name; + saveSettings(); +} + +void ClearBranchAction::triggered() +{ + stringSettings.otaServerBranch = {}; + saveSettings(); +} +} + +SelectBuildserverBranchMenu::SelectBuildserverBranchMenu() +{ + using namespace SelectBuildServerBranch; + + if (count_available_buildserver() < 1) + { + ERR_MESSAGE(TEXT_OTA_NOBUILDSERVERAVAILABLE); // E:No server saved. + } + + if (stringSettings.otaServerUrl.empty()) + { + ERR_MESSAGE(TEXT_OTA_NOBUILDSERVERSELECTED); // E:No server selected. + } + + if (const auto staStatus = wifi_stack::get_sta_status(); staStatus != wifi_stack::WiFiStaStatus::CONNECTED) + { + ERR_MESSAGE(TEXT_OTA_NOCONNECTION); // E:No internet. + } + + SelectBranch::setup_request(); + SelectBranch::start_descriptor_request(stringSettings.otaServerUrl); +} + +void SelectBuildserverBranchMenu::update() +{ + using namespace SelectBranch; + if(get_request_running()) + { + check_descriptor_request(); + if (!request_failed.empty()) + { + this->buildMenuRequestError(request_failed); + request_failed = {}; + } + } + + if (!constructedMenu && branches.size() > 0) + { + constructedMenu = true; + constructMenuItem>(); + constructMenuItem>(); + + for (const std::string &branch : branches) + { + if (branch.empty()) + continue; + auto &menuitem = constructMenuItem(); + menuitem.setName(branch); + } + + constructMenuItem>(); + constructMenuItem, ClearBranchAction, StaticMenuItemIcon<&bobbyicons::reboot>>>(); + constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>(); + } + Base::update(); +} + +void SelectBuildserverBranchMenu::back() +{ + switchScreen(); +} + +void SelectBuildserverBranchMenu::buildMenuRequestError(std::string error) +{ + auto &item = constructMenuItem, DummyAction>>(); + item.setTitle(error); + constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>(); +} +#endif diff --git a/main/displays/menus/selectbuildserverbranch.h b/main/displays/menus/selectbuildserverbranch.h new file mode 100644 index 0000000..d671846 --- /dev/null +++ b/main/displays/menus/selectbuildserverbranch.h @@ -0,0 +1,46 @@ +#pragma once + +// 3rd party includes +#include +#include +#ifdef FEATURE_OTA + +namespace SelectBuildServerBranch { + class CurrentBranch : public virtual espgui::TextInterface + { + public: + std::string text() const override; + }; + + class BranchMenuItem : public espgui::MenuItem + { + public: + std::string text() const override; + void setName(std::string &&name); + void setName(const std::string &name); + + void triggered() override; + private: + std::string m_name; + }; + + class ClearBranchAction : public virtual espgui::ActionInterface + { + public: + void triggered() override; + }; +} + +class SelectBuildserverBranchMenu : + public espgui::MenuDisplay, + public espgui::StaticText +{ + using Base = espgui::MenuDisplay; +public: + SelectBuildserverBranchMenu(); + void buildMenuRequestError(std::string error); + void update() override; + void back() override; +}; + +#endif diff --git a/main/presets.cpp b/main/presets.cpp index 7c3425d..14a16fb 100644 --- a/main/presets.cpp +++ b/main/presets.cpp @@ -51,6 +51,7 @@ StringSettings makeDefaultStringSettings() .otaServerUrl = {}, #endif .ap_password = STRING(AP_PASSWORD), + .otaServerBranch = {} }; } } // namespace presets diff --git a/main/stringsettings.h b/main/stringsettings.h index 2434d51..406bcab 100644 --- a/main/stringsettings.h +++ b/main/stringsettings.h @@ -49,6 +49,7 @@ struct StringSettings std::string dns_key; #endif std::string ap_password; + std::string otaServerBranch; }; template @@ -118,6 +119,7 @@ void StringSettings::executeForEveryCommonSetting(T &&callable) callable("dnskey", dns_key); #endif callable("ap_pw", ap_password); + callable("otaBranch", otaServerBranch); } template diff --git a/main/texts.cpp b/main/texts.cpp index 48b14f5..baed3b2 100644 --- a/main/texts.cpp +++ b/main/texts.cpp @@ -533,4 +533,8 @@ char TEXT_STATSCLEAR[] = "Clear current km"; char TEXT_POWERSUPPLY[] = "Powersupply"; #endif char TEXT_REENABLE_MENUITEMS[] = "Show advanced"; + +//SelectBuildserverBranchMenu +char TEXT_SELECT_BRANCH[] = "Select Branch"; +char TEXT_SELECT_BRANCH_CLEAR[] = "Clear Branch"; } // namespace diff --git a/main/texts.h b/main/texts.h index d260a23..b3b9a74 100644 --- a/main/texts.h +++ b/main/texts.h @@ -532,6 +532,10 @@ extern char TEXT_STATSCLEAR[]; extern char TEXT_POWERSUPPLY[]; #endif extern char TEXT_REENABLE_MENUITEMS[]; + +//SelectBuildserverBranchMenu +extern char TEXT_SELECT_BRANCH[]; +extern char TEXT_SELECT_BRANCH_CLEAR[]; } // namespace using namespace bobbytexts;