mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-18 19:03:16 +00:00
Merge develop into main (#377)
- Extract web server from `DevelopmentService` into a separate class: `HttpServer` - Export more functions in `tt_init.cpp`
This commit is contained in:
parent
d8346998ce
commit
9c5a427a34
71
Tactility/Include/Tactility/network/HttpServer.h
Normal file
71
Tactility/Include/Tactility/network/HttpServer.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
|
||||||
|
#include <esp_http_server.h>
|
||||||
|
#include <Tactility/Mutex.h>
|
||||||
|
#include <Tactility/kernel/SystemEvents.h>
|
||||||
|
|
||||||
|
namespace tt::network {
|
||||||
|
|
||||||
|
class HttpServer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function for URI matching used by server.
|
||||||
|
*
|
||||||
|
* @param[in] referenceUri URI/template with respect to which the other URI is matched
|
||||||
|
* @param[in] uriToCheck URI/template being matched to the reference URI/template
|
||||||
|
* @param[in] matchUpTo For specifying the actual length of `uri_to_match` up to
|
||||||
|
* which the matching algorithm is to be applied (The maximum
|
||||||
|
* value is `strlen(uri_to_match)`, independent of the length
|
||||||
|
* of `reference_uri`)
|
||||||
|
* @return true on match
|
||||||
|
*/
|
||||||
|
typedef bool (*UriMatchFunction)(const char* referenceUri, const char* uriToCheck, size_t matchUpTo);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const uint32_t port;
|
||||||
|
const std::string address;
|
||||||
|
const uint32_t stackSize;
|
||||||
|
const UriMatchFunction matchUri;
|
||||||
|
|
||||||
|
std::vector<httpd_uri_t> handlers;
|
||||||
|
|
||||||
|
Mutex mutex = Mutex(Mutex::Type::Recursive);
|
||||||
|
httpd_handle_t server = nullptr;
|
||||||
|
|
||||||
|
bool startInternal();
|
||||||
|
void stopInternal();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
HttpServer(
|
||||||
|
uint32_t port,
|
||||||
|
const std::string& address,
|
||||||
|
std::vector<httpd_uri_t> handlers,
|
||||||
|
uint32_t stackSize = 5120,
|
||||||
|
UriMatchFunction matchUri = httpd_uri_match_wildcard
|
||||||
|
) :
|
||||||
|
port(port),
|
||||||
|
address(address),
|
||||||
|
stackSize(stackSize),
|
||||||
|
matchUri(matchUri),
|
||||||
|
handlers(handlers)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void start();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
bool isStarted() const {
|
||||||
|
auto lock = mutex.asScopedLock();
|
||||||
|
lock.lock();
|
||||||
|
return server != nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -7,49 +7,44 @@
|
|||||||
|
|
||||||
#include <esp_event.h>
|
#include <esp_event.h>
|
||||||
#include <esp_http_server.h>
|
#include <esp_http_server.h>
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
#include <Tactility/network/HttpServer.h>
|
||||||
|
|
||||||
namespace tt::service::development {
|
namespace tt::service::development {
|
||||||
|
|
||||||
class DevelopmentService final : public Service {
|
class DevelopmentService final : public Service {
|
||||||
|
|
||||||
Mutex mutex = Mutex(Mutex::Type::Recursive);
|
Mutex mutex = Mutex(Mutex::Type::Recursive);
|
||||||
httpd_handle_t server = nullptr;
|
|
||||||
bool enabled = false;
|
|
||||||
kernel::SystemEventSubscription networkConnectEventSubscription = 0;
|
|
||||||
kernel::SystemEventSubscription networkDisconnectEventSubscription = 0;
|
|
||||||
std::string deviceResponse;
|
std::string deviceResponse;
|
||||||
|
network::HttpServer httpServer = network::HttpServer(
|
||||||
httpd_uri_t handleGetInfoEndpoint = {
|
6666,
|
||||||
.uri = "/info",
|
"0.0.0.0",
|
||||||
.method = HTTP_GET,
|
std::vector<httpd_uri_t>{
|
||||||
.handler = handleGetInfo,
|
{
|
||||||
.user_ctx = this
|
.uri = "/info",
|
||||||
};
|
.method = HTTP_GET,
|
||||||
|
.handler = handleGetInfo,
|
||||||
httpd_uri_t appRunEndpoint = {
|
.user_ctx = this
|
||||||
.uri = "/app/run",
|
},
|
||||||
.method = HTTP_POST,
|
{
|
||||||
.handler = handleAppRun,
|
.uri = "/app/run",
|
||||||
.user_ctx = this
|
.method = HTTP_POST,
|
||||||
};
|
.handler = handleAppRun,
|
||||||
|
.user_ctx = this
|
||||||
httpd_uri_t appInstallEndpoint = {
|
},
|
||||||
.uri = "/app/install",
|
{
|
||||||
.method = HTTP_PUT,
|
.uri = "/app/install",
|
||||||
.handler = handleAppInstall,
|
.method = HTTP_PUT,
|
||||||
.user_ctx = this
|
.handler = handleAppInstall,
|
||||||
};
|
.user_ctx = this
|
||||||
|
},
|
||||||
httpd_uri_t appUninstallEndpoint = {
|
{
|
||||||
.uri = "/app/uninstall",
|
.uri = "/app/uninstall",
|
||||||
.method = HTTP_PUT,
|
.method = HTTP_PUT,
|
||||||
.handler = handleAppUninstall,
|
.handler = handleAppUninstall,
|
||||||
.user_ctx = this
|
.user_ctx = this
|
||||||
};
|
}
|
||||||
|
}
|
||||||
void onNetworkConnected();
|
);
|
||||||
void onNetworkDisconnected();
|
|
||||||
|
|
||||||
void startServer();
|
void startServer();
|
||||||
void stopServer();
|
void stopServer();
|
||||||
@ -64,6 +59,7 @@ public:
|
|||||||
// region Overrides
|
// region Overrides
|
||||||
|
|
||||||
bool onStart(ServiceContext& service) override;
|
bool onStart(ServiceContext& service) override;
|
||||||
|
|
||||||
void onStop(ServiceContext& service) override;
|
void onStop(ServiceContext& service) override;
|
||||||
|
|
||||||
// endregion Overrides
|
// endregion Overrides
|
||||||
@ -81,10 +77,6 @@ public:
|
|||||||
* @param[in] enabled
|
* @param[in] enabled
|
||||||
*/
|
*/
|
||||||
void setEnabled(bool enabled);
|
void setEnabled(bool enabled);
|
||||||
|
|
||||||
bool isStarted() const;
|
|
||||||
|
|
||||||
// region Internal API
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<DevelopmentService> findService();
|
std::shared_ptr<DevelopmentService> findService();
|
||||||
|
|||||||
@ -65,14 +65,14 @@ class DevelopmentApp final : public App {
|
|||||||
void updateViewState() {
|
void updateViewState() {
|
||||||
if (!service->isEnabled()) {
|
if (!service->isEnabled()) {
|
||||||
lv_label_set_text(statusLabel, "Service disabled");
|
lv_label_set_text(statusLabel, "Service disabled");
|
||||||
} else if (!service->isStarted()) {
|
} else if (service::wifi::getRadioState() != service::wifi::RadioState::ConnectionActive) {
|
||||||
lv_label_set_text(statusLabel, "Waiting for connection...");
|
lv_label_set_text(statusLabel, "Waiting for connection...");
|
||||||
} else { // enabled and started
|
} else { // enabled and connected to wifi
|
||||||
auto ip = service::wifi::getIp();
|
auto ip = service::wifi::getIp();
|
||||||
if (ip.empty()) {
|
if (ip.empty()) {
|
||||||
lv_label_set_text(statusLabel, "Waiting for IP...");
|
lv_label_set_text(statusLabel, "Waiting for IP...");
|
||||||
} else {
|
} else {
|
||||||
const std::string status = std::string("Available at ") + ip;
|
const std::string status = std::format("Available at {}", ip);
|
||||||
lv_label_set_text(statusLabel, status.c_str());
|
lv_label_set_text(statusLabel, status.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
58
Tactility/Source/network/HttpServer.cpp
Normal file
58
Tactility/Source/network/HttpServer.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
|
||||||
|
#include <Tactility/network/HttpServer.h>
|
||||||
|
#include <Tactility/service/wifi/Wifi.h>
|
||||||
|
|
||||||
|
namespace tt::network {
|
||||||
|
|
||||||
|
constexpr auto* TAG = "HttpServer";
|
||||||
|
|
||||||
|
bool HttpServer::startInternal() {
|
||||||
|
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||||
|
config.stack_size = stackSize;
|
||||||
|
config.server_port = port;
|
||||||
|
config.uri_match_fn = matchUri;
|
||||||
|
|
||||||
|
if (httpd_start(&server, &config) != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "Failed to start http server on port %d", port);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::vector<httpd_uri_t>::reference handler : handlers) {
|
||||||
|
httpd_register_uri_handler(server, &handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
TT_LOG_I(TAG, "Started on port %d", config.server_port);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpServer::stopInternal() {
|
||||||
|
TT_LOG_I(TAG, "Stopping server");
|
||||||
|
if (server != nullptr && httpd_stop(server) != ESP_OK) {
|
||||||
|
TT_LOG_W(TAG, "Error while stopping");
|
||||||
|
server = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpServer::start() {
|
||||||
|
auto lock = mutex.asScopedLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
startInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpServer::stop() {
|
||||||
|
auto lock = mutex.asScopedLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
if (!isStarted()) {
|
||||||
|
TT_LOG_W(TAG, "Not started");
|
||||||
|
}
|
||||||
|
|
||||||
|
stopInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -9,17 +9,11 @@
|
|||||||
#include <Tactility/network/Url.h>
|
#include <Tactility/network/Url.h>
|
||||||
#include <Tactility/Paths.h>
|
#include <Tactility/Paths.h>
|
||||||
#include <Tactility/service/development/DevelopmentSettings.h>
|
#include <Tactility/service/development/DevelopmentSettings.h>
|
||||||
#include <Tactility/service/ServiceManifest.h>
|
|
||||||
#include <Tactility/service/ServiceRegistration.h>
|
#include <Tactility/service/ServiceRegistration.h>
|
||||||
#include <Tactility/service/wifi/Wifi.h>
|
|
||||||
#include <Tactility/StringUtils.h>
|
#include <Tactility/StringUtils.h>
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <esp_wifi.h>
|
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <Tactility/Tactility.h>
|
|
||||||
#include <Tactility/file/FileLock.h>
|
|
||||||
|
|
||||||
namespace tt::service::development {
|
namespace tt::service::development {
|
||||||
|
|
||||||
@ -28,70 +22,6 @@ extern const ServiceManifest manifest;
|
|||||||
constexpr const char* TAG = "DevService";
|
constexpr const char* TAG = "DevService";
|
||||||
|
|
||||||
bool DevelopmentService::onStart(ServiceContext& service) {
|
bool DevelopmentService::onStart(ServiceContext& service) {
|
||||||
auto lock = mutex.asScopedLock();
|
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
networkConnectEventSubscription = kernel::subscribeSystemEvent(
|
|
||||||
kernel::SystemEvent::NetworkConnected,
|
|
||||||
[this](kernel::SystemEvent) { onNetworkConnected(); }
|
|
||||||
);
|
|
||||||
networkConnectEventSubscription = kernel::subscribeSystemEvent(
|
|
||||||
kernel::SystemEvent::NetworkDisconnected,
|
|
||||||
[this](kernel::SystemEvent) { onNetworkDisconnected(); }
|
|
||||||
);
|
|
||||||
|
|
||||||
setEnabled(shouldEnableOnBoot());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DevelopmentService::onStop(ServiceContext& service) {
|
|
||||||
auto lock = mutex.asScopedLock();
|
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
kernel::unsubscribeSystemEvent(networkConnectEventSubscription);
|
|
||||||
kernel::unsubscribeSystemEvent(networkDisconnectEventSubscription);
|
|
||||||
|
|
||||||
if (isEnabled()) {
|
|
||||||
setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// region Enable/disable
|
|
||||||
|
|
||||||
void DevelopmentService::setEnabled(bool enabled) {
|
|
||||||
auto lock = mutex.asScopedLock();
|
|
||||||
lock.lock();
|
|
||||||
this->enabled = enabled;
|
|
||||||
|
|
||||||
// We might already have an IP address, so in case we do, we start the server manually
|
|
||||||
// Or we started the server while it shouldn't be
|
|
||||||
if (enabled && !isStarted() && wifi::getRadioState() == wifi::RadioState::ConnectionActive) {
|
|
||||||
startServer();
|
|
||||||
} else if (!enabled && isStarted()) {
|
|
||||||
stopServer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DevelopmentService::isEnabled() const {
|
|
||||||
auto lock = mutex.asScopedLock();
|
|
||||||
lock.lock();
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
// region Enable/disable
|
|
||||||
|
|
||||||
void DevelopmentService::startServer() {
|
|
||||||
auto lock = mutex.asScopedLock();
|
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
if (isStarted()) {
|
|
||||||
TT_LOG_W(TAG, "Already started");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Starting server");
|
|
||||||
|
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
stream << "{";
|
stream << "{";
|
||||||
stream << "\"cpuFamily\":\"" << CONFIG_IDF_TARGET << "\", ";
|
stream << "\"cpuFamily\":\"" << CONFIG_IDF_TARGET << "\", ";
|
||||||
@ -100,61 +30,36 @@ void DevelopmentService::startServer() {
|
|||||||
stream << "}";
|
stream << "}";
|
||||||
deviceResponse = stream.str();
|
deviceResponse = stream.str();
|
||||||
|
|
||||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
setEnabled(shouldEnableOnBoot());
|
||||||
config.stack_size = 5120;
|
|
||||||
|
|
||||||
config.server_port = 6666;
|
return true;
|
||||||
config.uri_match_fn = httpd_uri_match_wildcard;
|
}
|
||||||
|
|
||||||
if (httpd_start(&server, &config) == ESP_OK) {
|
void DevelopmentService::onStop(ServiceContext& service) {
|
||||||
httpd_register_uri_handler(server, &handleGetInfoEndpoint);
|
setEnabled(false);
|
||||||
httpd_register_uri_handler(server, &appRunEndpoint);
|
}
|
||||||
httpd_register_uri_handler(server, &appInstallEndpoint);
|
|
||||||
httpd_register_uri_handler(server, &appUninstallEndpoint);
|
// region Enable/disable
|
||||||
TT_LOG_I(TAG, "Started on port %d", config.server_port);
|
|
||||||
|
void DevelopmentService::setEnabled(bool enabled) {
|
||||||
|
auto lock = mutex.asScopedLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
if (!httpServer.isStarted()) {
|
||||||
|
httpServer.start();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
TT_LOG_E(TAG, "Failed to start");
|
if (httpServer.isStarted()) {
|
||||||
|
httpServer.stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevelopmentService::stopServer() {
|
bool DevelopmentService::isEnabled() const {
|
||||||
auto lock = mutex.asScopedLock();
|
auto lock = mutex.asScopedLock();
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
return httpServer.isStarted();
|
||||||
if (!isStarted()) {
|
|
||||||
TT_LOG_W(TAG, "Not started");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TT_LOG_I(TAG, "Stopping server");
|
|
||||||
if (httpd_stop(server) != ESP_OK) {
|
|
||||||
TT_LOG_W(TAG, "Error while stopping");
|
|
||||||
}
|
|
||||||
server = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DevelopmentService::isStarted() const {
|
|
||||||
auto lock = mutex.asScopedLock();
|
|
||||||
lock.lock();
|
|
||||||
return server != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DevelopmentService::onNetworkConnected() {
|
|
||||||
TT_LOG_I(TAG, "onNetworkConnected");
|
|
||||||
mutex.withLock([this] {
|
|
||||||
if (isEnabled() && !isStarted()) {
|
|
||||||
startServer();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void DevelopmentService::onNetworkDisconnected() {
|
|
||||||
TT_LOG_I(TAG, "onNetworkDisconnected");
|
|
||||||
mutex.withLock([this] {
|
|
||||||
if (isStarted()) {
|
|
||||||
stopServer();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// region endpoints
|
// region endpoints
|
||||||
|
|||||||
@ -379,6 +379,11 @@ const esp_elfsym main_symbols[] {
|
|||||||
ESP_ELFSYM_EXPORT(lv_obj_set_flex_align),
|
ESP_ELFSYM_EXPORT(lv_obj_set_flex_align),
|
||||||
ESP_ELFSYM_EXPORT(lv_obj_set_flex_flow),
|
ESP_ELFSYM_EXPORT(lv_obj_set_flex_flow),
|
||||||
ESP_ELFSYM_EXPORT(lv_obj_set_flex_grow),
|
ESP_ELFSYM_EXPORT(lv_obj_set_flex_grow),
|
||||||
|
ESP_ELFSYM_EXPORT(lv_obj_set_layout),
|
||||||
|
ESP_ELFSYM_EXPORT(lv_obj_is_layout_positioned),
|
||||||
|
ESP_ELFSYM_EXPORT(lv_obj_mark_layout_as_dirty),
|
||||||
|
ESP_ELFSYM_EXPORT(lv_obj_get_style_layout),
|
||||||
|
ESP_ELFSYM_EXPORT(lv_obj_update_layout),
|
||||||
ESP_ELFSYM_EXPORT(lv_obj_set_scroll_dir),
|
ESP_ELFSYM_EXPORT(lv_obj_set_scroll_dir),
|
||||||
ESP_ELFSYM_EXPORT(lv_obj_set_style_radius),
|
ESP_ELFSYM_EXPORT(lv_obj_set_style_radius),
|
||||||
ESP_ELFSYM_EXPORT(lv_obj_set_style_border_width),
|
ESP_ELFSYM_EXPORT(lv_obj_set_style_border_width),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user