SensESP 3.0.1
Universal Signal K sensor toolkit ESP32
Loading...
Searching...
No Matches
signalk_put_request.cpp
Go to the documentation of this file.
2
4#include "sensesp_app.h"
5
6namespace sensesp {
7
8std::map<String, SKRequest::PendingRequest*> SKRequest::request_map_;
9
10String SKRequest::send_request(JsonDocument& request,
11 std::function<void(JsonDocument&)> callback,
12 uint32_t timeout) {
13 // Create a new PendingRequest object to track this request...
14 auto* pending_request = new PendingRequest();
15
16 // Generate a uuid for the request...
17 pending_request->request_id = generate_uuid4();
18
19 // Save the callback for future processing...
20 pending_request->callback = callback;
21
22 // After 10 seconds, if we haven't already handled a response,
23 // assume its not coming.
24 pending_request->timeout_cleanup =
25 event_loop()->onDelay(timeout, [pending_request]() {
26 // Mark the delay eventll as it will be cleaned up by the ReactESP
27 // framework if this executes...
28 ESP_LOGW(__FILENAME__, "No response from server for request Id %s",
29 pending_request->request_id.c_str());
30 pending_request->timeout_cleanup = nullptr;
31 SKRequest::remove_request(pending_request->request_id);
32 });
33
34 request_map_[pending_request->request_id] = pending_request;
35
36 // Now, send the actual request to the server...
37 request["requestId"] = pending_request->request_id;
38
39 String request_txt;
40 serializeJson(request, request_txt);
41 ESP_LOGD(__FILENAME__, "Sending websocket request to server: %s",
42 request_txt.c_str());
43
44 SensESPApp::get()->get_ws_client()->sendTXT(request_txt);
45
46 return pending_request->request_id;
47}
48
50 auto iterator = request_map_.find(request_id);
51 if (iterator != request_map_.end()) {
52 return (iterator->second);
53 }
54 return nullptr;
55}
56
57void SKRequest::handle_response(JsonDocument& response) {
58 String request_id = response["requestId"];
59 PendingRequest* pending_request = get_request(request_id);
60 if (pending_request != nullptr) {
61 pending_request->callback(response);
62
63 // Now, are we done?
64 String state = response["state"];
65 if (!state.equalsIgnoreCase("PENDING")) {
66 remove_request(request_id);
67 }
68 } else {
69 ESP_LOGW(__FILENAME__,
70 "Received request response for an untracked request: %s",
71 request_id.c_str());
72 }
73}
74
75void SKRequest::remove_request(String request_id) {
76 PendingRequest* pending_request = SKRequest::get_request(request_id);
77 if (pending_request != nullptr) {
78 // First, stop any pending timeout handlers...
79 if (pending_request->timeout_cleanup != nullptr) {
80 // The timeout code was not called, so just
81 // remove it from the ReactESP execution queue...
82 pending_request->timeout_cleanup->remove(
83 event_loop());
84 }
85
86 // Now, remove the request from the map...
87 request_map_.erase(request_id);
88
89 // Finally, discard the request tracker...
90 delete pending_request;
91 }
92}
93
95 const String& config_path, uint32_t timeout)
96 : FileSystemSaveable(config_path), sk_path{sk_path}, timeout{timeout} {
97 load();
98}
99
101 JsonDocument doc;
102 JsonObject root = doc.to<JsonObject>();
103 JsonObject put_data = root["put"].to<JsonObject>();
104 put_data["path"] = sk_path;
105 set_put_value(put_data);
107 doc, [this](JsonDocument& response) { this->on_response(response); },
108 timeout);
109}
110
112 return (get_request(this->pending_request_id_) != nullptr);
113}
114
115void SKPutRequestBase::on_response(JsonDocument& response) {
116 String request_id = response["requestId"];
117 String state = response["state"];
118 ESP_LOGD(__FILENAME__, "Response %s received for PUT request: %s",
119 state.c_str(), request_id.c_str());
120}
121
122bool SKPutRequestBase::to_json(JsonObject& root) {
123 root["sk_path"] = sk_path;
124 return true;
125}
126
127bool SKPutRequestBase::from_json(const JsonObject& config) {
128 const String expected[] = {"sk_path"};
129 for (auto str : expected) {
130 if (!config[str].is<JsonVariant>()) {
131 return false;
132 }
133 }
134 this->sk_path = config["sk_path"].as<String>();
135 return true;
136}
137
138} // namespace sensesp
virtual bool load() override
Load and populate the object from a persistent storage.
Definition saveable.cpp:8
virtual void set_put_value(JsonObject &put_data)=0
SKPutRequestBase(const String &sk_path, const String &config_path="", uint32_t timeout=5000)
virtual bool from_json(const JsonObject &config) override
virtual bool to_json(JsonObject &root) override
virtual void on_response(JsonDocument &response)
std::function< void(JsonDocument &)> callback
static void handle_response(JsonDocument &response)
static String send_request(JsonDocument &request, std::function< void(JsonDocument &)> callback, uint32_t timeout=5000)
static PendingRequest * get_request(String request_id)
static std::map< String, PendingRequest * > request_map_
static void remove_request(String request_id)
static std::shared_ptr< SensESPApp > get()
Get the singleton instance of the SensESPApp.
Definition sensesp_app.h:57
std::shared_ptr< reactesp::EventLoop > event_loop()
Definition sensesp.cpp:9
String generate_uuid4()
Generate a random UUIDv4 string.
Definition uuid.cpp:5