-
Notifications
You must be signed in to change notification settings - Fork 21
refactor: Replace Arduino HTTP Client with esp native #391
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
657ab37
ff81cf6
22dc664
8ceac76
042f28d
50e317f
9dcc162
49be717
eb734c7
c342d31
664a589
9604c39
d7774cc
0d966e3
979a17d
8cc417b
c0ee503
e8d2790
d83d888
3a274f5
bb36316
c44bbc0
0bfc377
454a508
a6bc157
7e79d41
614e4c8
68cf530
b59e4b9
435e6ef
3579cee
c9f2094
da86842
3de2c16
f752a17
441688f
6b85a36
03ad6f8
33144d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| #pragma once | ||
|
|
||
| #include <cstdint> | ||
| #include <functional> | ||
|
|
||
| namespace OpenShock::HTTP { | ||
| using DownloadCallback = std::function<bool(std::size_t offset, const uint8_t* data, std::size_t len)>; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| #pragma once | ||
|
|
||
| #include "Common.h" | ||
| #include "http/HTTPClientState.h" | ||
| #include "http/HTTPResponse.h" | ||
| #include "http/JsonResponse.h" | ||
| #include "RateLimiter.h" | ||
|
|
||
| #include <esp_err.h> | ||
|
|
||
| #include <cstdint> | ||
| #include <memory> | ||
|
|
||
| namespace OpenShock::HTTP { | ||
| class HTTPClient { | ||
|
Check warning on line 15 in include/http/HTTPClient.h
|
||
| DISABLE_COPY(HTTPClient); | ||
| DISABLE_MOVE(HTTPClient); | ||
|
|
||
| public: | ||
| HTTPClient(const char* url, uint32_t timeoutMs = 10'000) | ||
|
Check warning on line 20 in include/http/HTTPClient.h
|
||
| : m_state(std::make_shared<HTTPClientState>(url, timeoutMs)) | ||
| { | ||
| } | ||
|
|
||
| inline esp_err_t SetUrl(const char* url) { | ||
|
Check warning on line 25 in include/http/HTTPClient.h
|
||
| return m_state->SetUrl(url); | ||
| } | ||
|
|
||
| inline esp_err_t SetHeader(const char* key, const char* value) { | ||
| return m_state->SetHeader(key, value); | ||
| } | ||
|
|
||
| inline HTTPResponse Get() { | ||
| auto response = m_state->StartRequest(HTTP_METHOD_GET, 0); | ||
| if (response.error != HTTPError::None) return HTTP::HTTPResponse(response.error, response.retryAfterSeconds); | ||
|
|
||
| return HTTP::HTTPResponse(m_state, response.statusCode, response.contentLength, std::move(response.headers)); | ||
| } | ||
| template<typename T> | ||
| inline JsonResponse<T> GetJson(JsonParserFn<T> jsonParser) { | ||
| auto response = m_state->StartRequest(HTTP_METHOD_GET, 0); | ||
| if (response.error != HTTPError::None) return HTTP::JsonResponse<T>(response.error, response.retryAfterSeconds); | ||
|
|
||
| return HTTP::JsonResponse(m_state, jsonParser, response.statusCode, response.contentLength, std::move(response.headers)); | ||
| } | ||
|
|
||
| inline esp_err_t Close() { | ||
| return m_state->Close(); | ||
| } | ||
| private: | ||
| std::shared_ptr<HTTPClientState> m_state; | ||
| }; | ||
| } // namespace OpenShock::HTTP | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| #pragma once | ||
|
|
||
| #include "Common.h" | ||
| #include "http/DownloadCallback.h" | ||
| #include "http/HTTPError.h" | ||
| #include "http/JsonParserFn.h" | ||
| #include "http/ReadResult.h" | ||
|
|
||
| #include <cJSON.h> | ||
|
|
||
| #include <esp_http_client.h> | ||
|
|
||
| #include <map> | ||
| #include <string> | ||
| #include <string_view> | ||
|
|
||
| namespace OpenShock::HTTP { | ||
| class HTTPClientState { | ||
| DISABLE_COPY(HTTPClientState); | ||
| DISABLE_MOVE(HTTPClientState); | ||
| public: | ||
| HTTPClientState(const char* url, uint32_t timeoutMs); | ||
| ~HTTPClientState(); | ||
|
|
||
| esp_err_t SetUrl(const char* url); | ||
|
|
||
| esp_err_t SetHeader(const char* key, const char* value); | ||
|
|
||
| struct HeaderEntry { | ||
| std::string key; | ||
| std::string value; | ||
| }; | ||
|
|
||
| struct [[nodiscard]] StartRequestResult { | ||
| HTTPError error{}; | ||
| uint32_t retryAfterSeconds{}; | ||
| uint16_t statusCode{}; | ||
| bool isChunked{}; | ||
| uint32_t contentLength{}; | ||
| std::map<std::string, std::string> headers{}; | ||
| }; | ||
|
|
||
| StartRequestResult StartRequest(esp_http_client_method_t method, int writeLen); | ||
|
|
||
| // High-throughput streaming logic | ||
| ReadResult<uint32_t> ReadStreamImpl(DownloadCallback cb); | ||
|
|
||
| ReadResult<std::string> ReadStringImpl(uint32_t reserve); | ||
|
|
||
| template<typename T> | ||
| inline ReadResult<T> ReadJsonImpl(uint32_t reserve, JsonParserFn<T> jsonParser) | ||
| { | ||
| auto response = ReadStringImpl(reserve); | ||
| if (response.error != HTTPError::None) { | ||
| return response.error; | ||
| } | ||
|
|
||
| cJSON* json = cJSON_ParseWithLength(response.data.c_str(), response.data.length()); | ||
| if (json == nullptr) { | ||
| return HTTPError::ParseFailed; | ||
| } | ||
|
|
||
| T data; | ||
| if (!jsonParser(json, data)) { | ||
| return HTTPError::ParseFailed; | ||
| } | ||
|
|
||
| cJSON_Delete(json); | ||
|
|
||
| return data; | ||
| } | ||
|
|
||
| inline esp_err_t Close() { | ||
| if (m_handle == nullptr) return ESP_FAIL; | ||
| return esp_http_client_close(m_handle); | ||
| } | ||
| private: | ||
| static esp_err_t EventHandler(esp_http_client_event_t* evt); | ||
| esp_err_t EventHeaderHandler(std::string key, std::string value); | ||
|
|
||
| esp_http_client_handle_t m_handle; | ||
| bool m_reading; | ||
| uint32_t m_retryAfterSeconds; | ||
| std::map<std::string, std::string> m_headers; | ||
| }; | ||
| } // namespace OpenShock::HTTP |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| #pragma once | ||
|
|
||
| namespace OpenShock::HTTP { | ||
| enum class HTTPError { | ||
| None, | ||
| ClientBusy, | ||
| InternalError, | ||
| RateLimited, | ||
| InvalidUrl, | ||
| InvalidHttpMethod, | ||
| NetworkError, | ||
| ConnectionClosed, | ||
| SizeLimitExceeded, | ||
| Aborted, | ||
| ParseFailed | ||
| }; | ||
|
|
||
| inline const char* HTTPErrorToString(HTTPError error) { | ||
| switch (error) | ||
| { | ||
| case HTTPError::None: | ||
| return "None"; | ||
| case HTTPError::ClientBusy: | ||
| return "ClientBusy"; | ||
| case HTTPError::InternalError: | ||
| return "InternalError"; | ||
| case HTTPError::RateLimited: | ||
| return "RateLimited"; | ||
| case HTTPError::InvalidUrl: | ||
| return "InvalidUrl"; | ||
| case HTTPError::InvalidHttpMethod: | ||
| return "InvalidHttpMethod"; | ||
| case HTTPError::NetworkError: | ||
| return "NetworkError"; | ||
| case HTTPError::ConnectionClosed: | ||
| return "ConnectionClosed"; | ||
| case HTTPError::SizeLimitExceeded: | ||
| return "SizeLimitExceeded"; | ||
| case HTTPError::Aborted: | ||
| return "Aborted"; | ||
| case HTTPError::ParseFailed: | ||
| return "ParseFailed"; | ||
| default: | ||
| return "Unknown"; | ||
| } | ||
| } | ||
| } // namespace OpenShock::HTTP |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| #pragma once | ||
|
|
||
| #include "Common.h" | ||
| #include "http/DownloadCallback.h" | ||
| #include "http/HTTPClientState.h" | ||
| #include "http/JsonParserFn.h" | ||
| #include "http/ReadResult.h" | ||
|
|
||
| #include <cstdint> | ||
| #include <map> | ||
| #include <memory> | ||
| #include <string> | ||
|
|
||
| namespace OpenShock::HTTP { | ||
| class HTTPClient; | ||
| class [[nodiscard]] HTTPResponse { | ||
| DISABLE_DEFAULT(HTTPResponse); | ||
| DISABLE_COPY(HTTPResponse); | ||
| DISABLE_MOVE(HTTPResponse); | ||
|
|
||
| friend class HTTPClient; | ||
|
|
||
| HTTPResponse(std::shared_ptr<HTTPClientState> state, uint16_t statusCode, uint32_t contentLength, std::map<std::string, std::string> headers) | ||
| : m_state(state) | ||
| , m_error(HTTPError::None) | ||
| , m_retryAfterSeconds(0) | ||
| , m_statusCode(statusCode) | ||
| , m_contentLength(contentLength) | ||
| , m_headers(std::move(headers)) | ||
| { | ||
| } | ||
| public: | ||
| HTTPResponse(HTTPError error) | ||
| : m_state() | ||
| , m_error(error) | ||
| , m_retryAfterSeconds() | ||
| , m_statusCode(0) | ||
| , m_contentLength(0) | ||
| , m_headers() | ||
| { | ||
| } | ||
| HTTPResponse(HTTPError error, uint32_t retryAfterSeconds) | ||
| : m_state() | ||
| , m_error(error) | ||
| , m_retryAfterSeconds(retryAfterSeconds) | ||
| , m_statusCode(0) | ||
| , m_contentLength(0) | ||
| , m_headers() | ||
| { | ||
| } | ||
|
|
||
| inline bool Ok() const { return m_error == HTTPError::None && !m_state.expired(); } | ||
| inline HTTPError Error() const { return m_error; } | ||
| inline uint32_t RetryAfterSeconds() const { return m_retryAfterSeconds; } | ||
| inline uint16_t StatusCode() const { return m_statusCode; } | ||
| inline uint32_t ContentLength() const { return m_contentLength; } | ||
|
|
||
| inline ReadResult<uint32_t> ReadStream(DownloadCallback downloadCallback) { | ||
| auto locked = m_state.lock(); | ||
| if (locked == nullptr) return HTTPError::ConnectionClosed; | ||
|
|
||
| return locked->ReadStreamImpl(downloadCallback); | ||
| } | ||
|
|
||
| inline ReadResult<std::string> ReadString() { | ||
| auto locked = m_state.lock(); | ||
| if (locked == nullptr) return HTTPError::ConnectionClosed; | ||
|
|
||
| return locked->ReadStringImpl(m_contentLength); | ||
| } | ||
|
|
||
| template<typename T> | ||
| inline ReadResult<T> ReadJson(JsonParserFn<T> jsonParser) | ||
| { | ||
| auto locked = m_state.lock(); | ||
| if (locked == nullptr) return HTTPError::ConnectionClosed; | ||
|
|
||
| return locked->ReadJsonImpl(m_contentLength, jsonParser); | ||
| } | ||
| private: | ||
| std::weak_ptr<HTTPClientState> m_state; | ||
| HTTPError m_error; | ||
| uint32_t m_retryAfterSeconds; | ||
| uint16_t m_statusCode; | ||
| uint32_t m_contentLength; | ||
| std::map<std::string, std::string> m_headers; | ||
| }; | ||
| } // namespace OpenShock::HTTP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new HTTPClient implementation does not integrate with the rate limiting system. The old implementation called
_getRateLimiter()and checkedrateLimiter->tryRequest()before making requests. Without this integration, the application may exceed API rate limits and get blocked by the server. Consider integrating the RateLimiters::GetRateLimiter functionality into the HTTPClient.