SensESP 3.5.1-alpha
Universal Signal K sensor toolkit ESP32
Loading...
Searching...
No Matches
ui_button_handler.cpp
Go to the documentation of this file.
1#include "sensesp.h"
2
3#include "ui_button_handler.h"
4
7
8namespace sensesp {
9
10namespace {
11
12constexpr char kButtonsUriPrefix[] = "/api/buttons/";
13
14// Percent-encoding expands a character to up to three bytes, so the
15// encoded tail is bounded at three times the name limit before decoding.
16constexpr size_t kMaxEncodedNameLength = 3 * UIButton::kMaxNameLength;
17
18void add_button_list_handler(std::shared_ptr<HTTPServer>& server) {
19 auto handler = std::make_shared<HTTPRequestHandler>(
20 1 << HTTP_GET, "/api/buttons", [](httpd_req_t* req) {
21 JsonDocument json_doc;
22 JsonArray arr = json_doc.to<JsonArray>();
23
24 for (const auto& entry : UIButton::get_ui_buttons()) {
25 // The click endpoint cannot resolve longer names; listing them
26 // would render buttons that never work.
27 if (entry.second->get_name().length() > UIButton::kMaxNameLength) {
28 continue;
29 }
30 JsonObject obj = arr.add<JsonObject>();
31 obj["name"] = entry.second->get_name();
32 obj["title"] = entry.second->get_title();
33 obj["mustConfirm"] = entry.second->get_must_confirm();
34 }
35
36 String response;
37 serializeJson(json_doc, response);
38 httpd_resp_set_type(req, "application/json");
39 httpd_resp_sendstr(req, response.c_str());
40 return ESP_OK;
41 });
42 server->add_handler(handler);
43}
44
45void add_button_click_handler(std::shared_ptr<HTTPServer>& server) {
46 auto handler = std::make_shared<HTTPRequestHandler>(
47 1 << HTTP_POST, String(kButtonsUriPrefix) + "*", [](httpd_req_t* req) {
48 if (!check_origin(req)) {
49 return ESP_FAIL;
50 }
51
52 String url_tail = String(req->uri).substring(strlen(kButtonsUriPrefix));
53 int query_start = url_tail.indexOf('?');
54 if (query_start != -1) {
55 url_tail = url_tail.substring(0, query_start);
56 }
57 if (url_tail.length() > kMaxEncodedNameLength) {
58 httpd_resp_send_err(req, HTTPD_404_NOT_FOUND,
59 "No button found with that name");
60 return ESP_FAIL;
61 }
62 char name_cstr[kMaxEncodedNameLength + 1];
63 urldecode2(name_cstr, url_tail.c_str());
64 String name(name_cstr);
65 if (name.length() > UIButton::kMaxNameLength) {
66 httpd_resp_send_err(req, HTTPD_404_NOT_FOUND,
67 "No button found with that name");
68 return ESP_FAIL;
69 }
70
71 const auto& buttons = UIButton::get_ui_buttons();
72 auto it = buttons.find(name);
73 if (it == buttons.end()) {
74 httpd_resp_send_err(req, HTTPD_404_NOT_FOUND,
75 "No button found with that name");
76 return ESP_FAIL;
77 }
78
79 httpd_resp_set_type(req, "application/json");
80 httpd_resp_sendstr(req, "{\"status\":\"ok\"}");
81
82 // User callbacks belong on the event loop task: the httpd task stack
83 // is not sized for them, and they may touch event-loop-owned state.
84 // The shared_ptr copy keeps the button alive even if a callback
85 // mutates the registry. A 200 means the click was accepted, as with
86 // /api/device/reset and /api/device/restart.
87 auto button = it->second;
88 event_loop()->onDelay(0, [button]() { button->notify(); });
89 return ESP_OK;
90 });
91 server->add_handler(handler);
92}
93
94} // namespace
95
96void add_button_handlers(std::shared_ptr<HTTPServer>& server) {
97 add_button_list_handler(server);
98 add_button_click_handler(server);
99}
100
101} // namespace sensesp
static const std::map< String, std::shared_ptr< UIButton > > & get_ui_buttons()
Definition ui_button.h:30
static constexpr size_t kMaxNameLength
Longest button name the web UI click endpoint resolves.
Definition ui_button.h:21
std::shared_ptr< reactesp::EventLoop > event_loop()
Definition sensesp.cpp:9
bool check_origin(httpd_req_t *req)
void add_button_handlers(std::shared_ptr< HTTPServer > &server)
Handle HTTP requests to /api/buttons.
void urldecode2(char *dst, const char *src)