Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
657ab37
Initial commit
hhvrc Nov 14, 2024
ff81cf6
Merge branch 'develop' into feature/ditch-arduino-httpclient
hhvrc Jan 13, 2025
22dc664
Merge branch 'develop' into feature/ditch-arduino-httpclient
hhvrc Feb 4, 2025
8ceac76
Use helpers
hhvrc Feb 4, 2025
042f28d
Merge branch 'develop' into feature/ditch-arduino-httpclient
hhvrc Nov 23, 2025
50e317f
Merge branch 'develop' into feature/ditch-arduino-httpclient
hhvrc Dec 2, 2025
9dcc162
Some more stuff
hhvrc Dec 2, 2025
49be717
Merge branch 'develop' into feature/ditch-arduino-httpclient
hhvrc Dec 3, 2025
eb734c7
Push WIP
hhvrc Dec 3, 2025
c342d31
More work
hhvrc Dec 4, 2025
664a589
Merge branch 'develop' into feature/ditch-arduino-httpclient
hhvrc Dec 4, 2025
9604c39
More work
hhvrc Dec 4, 2025
d7774cc
More work on custom http client
hhvrc Dec 4, 2025
0d966e3
More wooooorkkkkk AAAAAAAAAAAAAAAAAAA
hhvrc Dec 5, 2025
979a17d
These are not needed lmao
hhvrc Dec 5, 2025
8cc417b
nvm...
hhvrc Dec 5, 2025
c0ee503
more work
hhvrc Dec 5, 2025
e8d2790
More fixes and touchup
hhvrc Dec 5, 2025
d83d888
Update HTTPClientState.cpp
hhvrc Dec 5, 2025
3a274f5
More work
hhvrc Dec 5, 2025
bb36316
Arduino is and always has been a shitty ecosystem
hhvrc Dec 5, 2025
c44bbc0
Merge branch 'develop' into feature/ditch-arduino-httpclient
hhvrc Dec 5, 2025
0bfc377
Revert nitpick
hhvrc Dec 5, 2025
454a508
Revert more nitpicking
hhvrc Dec 5, 2025
a6bc157
Pass along headers and Retry-After
hhvrc Dec 5, 2025
7e79d41
Fix more issues
hhvrc Dec 5, 2025
614e4c8
Last touchup
hhvrc Dec 5, 2025
68cf530
Update include/http/HTTPClient.h
hhvrc Dec 5, 2025
b59e4b9
Update src/util/DomainUtils.cpp
hhvrc Dec 5, 2025
435e6ef
Update src/util/DomainUtils.cpp
hhvrc Dec 5, 2025
3579cee
Update src/serial/command_handlers/authtoken.cpp
hhvrc Dec 5, 2025
c9f2094
Update src/util/ParitionUtils.cpp
hhvrc Dec 5, 2025
da86842
Fixed url assignment issues
hhvrc Dec 8, 2025
3de2c16
Update platformio.ini
hhvrc Dec 15, 2025
f752a17
Merge branch 'develop' into feature/ditch-arduino-httpclient
hhvrc Dec 15, 2025
441688f
Merge branch 'develop' into feature/ditch-arduino-httpclient
hhvrc Dec 17, 2025
6b85a36
Experiement with global CA store
hhvrc Dec 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/http/DownloadCallback.h
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)>;
}
53 changes: 53 additions & 0 deletions include/http/HTTPClient.h
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 {
DISABLE_COPY(HTTPClient);
DISABLE_MOVE(HTTPClient);

public:
HTTPClient(const char* url, uint32_t timeoutMs = 10'000)
: m_state(std::make_shared<HTTPClientState>(url, timeoutMs))
{
}
Comment on lines +20 to +23
Copy link

Copilot AI Dec 15, 2025

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 checked rateLimiter->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.

Copilot uses AI. Check for mistakes.

inline esp_err_t SetUrl(const char* url) {
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
86 changes: 86 additions & 0 deletions include/http/HTTPClientState.h
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
47 changes: 47 additions & 0 deletions include/http/HTTPError.h
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
88 changes: 0 additions & 88 deletions include/http/HTTPRequestManager.h

This file was deleted.

88 changes: 88 additions & 0 deletions include/http/HTTPResponse.h
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
Loading