Skip to content
Draft
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
38 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
03ad6f8
Apply suggestions from code review
hhvrc Mar 22, 2026
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)>;
}
8 changes: 8 additions & 0 deletions include/http/GotContentLengthCallback.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 GotContentLengthCallback = std::function<bool(int contentLength)>;
}
54 changes: 54 additions & 0 deletions include/http/HTTPClient.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#pragma once

#include "Common.h"
#include "http/HTTPClientState.h"
#include "http/HTTPResponse.h"
#include "http/JsonResponse.h"

#include<esp_err.h>
Comment thread
hhvrc marked this conversation as resolved.
Outdated

#include <cstdint>
#include <memory>

namespace OpenShock::HTTP {
class HTTPClient {
DISABLE_COPY(HTTPClient);
DISABLE_MOVE(HTTPClient);

public:
HTTPClient(uint32_t timeoutMs = 10'000)
: m_state(std::make_shared<HTTPClientState>(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 SetHeader(const char* key, const char* value) {
return m_state->SetHeader(key, value);
}

inline HTTPResponse Get(const char* url) {
auto response = GetInternal(url);
if (response.error != HTTPError::None) return response.error;

return HTTP::HTTPResponse(m_state, response.data.statusCode, response.data.contentLength);
}
template<typename T>
inline JsonResponse<T> GetJson(const char* url, JsonParserFn<T> jsonParser) {
auto response = GetInternal(url);
if (response.error != HTTPError::None) return response.error;

return HTTP::JsonResponse(m_state, jsonParser, response.data.statusCode, response.data.contentLength);
}

inline esp_err_t Close() {
return m_state->Close();
}
private:
struct InternalResult {
HTTPError error;
HTTPClientState::StartRequestResult data;
};
InternalResult GetInternal(const char* url);

std::shared_ptr<HTTPClientState> m_state;
};
} // namespace OpenShock::HTTP
77 changes: 77 additions & 0 deletions include/http/HTTPClientState.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#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 <string>
#include <string_view>
#include <variant>
#include <vector>

namespace OpenShock::HTTP {
class HTTPClientState {
DISABLE_COPY(HTTPClientState);
DISABLE_MOVE(HTTPClientState);
public:
HTTPClientState(uint32_t timeoutMs);
~HTTPClientState();

inline esp_err_t SetHeader(const char* key, const char* value) {
return esp_http_client_set_header(m_handle, key, value);
}

struct [[nodiscard]] StartRequestResult {
uint16_t statusCode;
bool isChunked;
uint32_t contentLength;
};

std::variant<StartRequestResult, HTTPError> StartRequest(esp_http_client_method_t method, const char* url, 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() {
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;
std::vector<std::pair<std::string, std::string>> m_headers;
};
} // namespace OpenShock::HTTP
44 changes: 44 additions & 0 deletions include/http/HTTPError.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

namespace OpenShock::HTTP {
enum class HTTPError {
None,
InternalError,
RateLimited,
InvalidUrl,
InvalidHttpMethod,
NetworkError,
ConnectionClosed,
SizeLimitExceeded,
Aborted,
ParseFailed
};

inline const char* HTTPErrorToString(HTTPError error) {
switch (error)
{
case HTTPError::None:
return "";
case HTTPError::InternalError:
return "";
case HTTPError::RateLimited:
return "";
case HTTPError::InvalidUrl:
return "";
case HTTPError::InvalidHttpMethod:
return "";
case HTTPError::NetworkError:
return "";
case HTTPError::ConnectionClosed:
return "";
case HTTPError::SizeLimitExceeded:
return "";
case HTTPError::Aborted:
return "";
case HTTPError::ParseFailed:
return "";
default:
return "";
Comment thread
hhvrc marked this conversation as resolved.
Outdated
}
}
} // namespace OpenShock::HTTP
88 changes: 0 additions & 88 deletions include/http/HTTPRequestManager.h

This file was deleted.

71 changes: 71 additions & 0 deletions include/http/HTTPResponse.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#pragma once

#include "Common.h"
#include "http/DownloadCallback.h"
#include "http/HTTPClientState.h"
#include "http/JsonParserFn.h"
#include "http/ReadResult.h"

#include <cstdint>
#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)
: m_state(state)
, m_error(HTTPError::None)
, m_statusCode(statusCode)
, m_contentLength(contentLength)
{
}
public:
HTTPResponse(HTTPError error)
: m_state()
, m_error(error)
, m_statusCode(0)
, m_contentLength(0)
{
}

inline bool Ok() const { return m_error == HTTPError::None && !m_state.expired(); }
inline HTTPError Error() const { return m_error; }
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;
uint16_t m_statusCode;
uint32_t m_contentLength;
};
} // namespace OpenShock::HTTP
9 changes: 5 additions & 4 deletions include/http/JsonAPI.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "http/HTTPRequestManager.h"
#include "http/HTTPClient.h"
#include "http/JsonResponse.h"
#include "serialization/JsonAPI.h"

#include <string_view>
Expand All @@ -9,15 +10,15 @@ namespace OpenShock::HTTP::JsonAPI {
/// @brief Links the hub to the account with the given account link code, returns the hub token. Valid response codes: 200, 404
/// @param hubToken
/// @return
HTTP::Response<Serialization::JsonAPI::AccountLinkResponse> LinkAccount(std::string_view accountLinkCode);
JsonResponse<Serialization::JsonAPI::AccountLinkResponse> LinkAccount(HTTP::HTTPClient& client, std::string_view accountLinkCode);

/// @brief Gets the hub info for the given hub token. Valid response codes: 200, 401
/// @param hubToken
/// @return
HTTP::Response<Serialization::JsonAPI::HubInfoResponse> GetHubInfo(std::string_view hubToken);
JsonResponse<Serialization::JsonAPI::HubInfoResponse> GetHubInfo(HTTP::HTTPClient& client, const char* hubToken);

/// @brief Requests a Live Control Gateway to connect to. Valid response codes: 200, 401
/// @param hubToken
/// @return
HTTP::Response<Serialization::JsonAPI::AssignLcgResponse> AssignLcg(std::string_view hubToken);
JsonResponse<Serialization::JsonAPI::AssignLcgResponse> AssignLcg(HTTP::HTTPClient& client, const char* hubToken);
} // namespace OpenShock::HTTP::JsonAPI
11 changes: 11 additions & 0 deletions include/http/JsonParserFn.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include <cstdint>
#include <functional>

class cJSON;

namespace OpenShock::HTTP {
template<typename T>
using JsonParserFn = std::function<bool(const cJSON* json, T& data)>;
}
Loading