Based on the learnings from https://github.com/crosspoint-reader/crosspoint-reader/pull/2074 , I wanted to bring the same buffer savings to the rest of our HTTP Client stack. That being said, HttpDownloader (fonts/OPDS) used the Arduino HTTPClient. HttpDownloader was the last consumer of the Arduino HTTPClient + NetworkClientSecure stack. OtaUpdater already runs on esp_http_client, so this drops the parallel HTTP/TLS implementation. It also fixes a class of OPDS/font download failures: HTTPClient's setTimeout is uint16 and truncates, and its short per-read deadline killed slow or chunked responses (the -11 / incomplete-data errors). What changed: - Rewrote fetchUrl/downloadToFile around esp_http_client with a streaming open() -> fetch_headers() -> read() loop, manual redirect following, and is_complete_data_received() as the completeness gate. Body bytes go straight to the sink (OPDS parser stream, std::string, or file), so nothing buffers the payload. - HTTPS is now verified against the CA bundle instead of NetworkClientSecure::setInsecure(). esp-tls is built with CONFIG_ESP_TLS_INSECURE off, so an unverified handshake can't be set up anyway; the model is public servers over verified https and local servers over plain http (transport is chosen from the URL scheme). ** Self-signed https servers are no longer supported, by design. ** - timeout_ms is 60s; esp_http_client's timeout is uint32, so unlike HTTPClient it doesn't silently truncate. - HTTP buffers are 4096 (rx) / 1024 (tx). 4096 holds real OPDS server headers; the GitHub release CDN sends more and logs a non-fatal truncation warning, but the headers we read (Location, Content-Length) come first and survive. - Removed the now-unused UrlUtils::isHttpsUrl and a stale HTTPClient comment in FontDownloadActivity. Validated on device: OPDS browse and a 3.4 MB book download over verified https, GitHub font downloads (crc-checked), redirect handling matching curl, and slow/erroring servers surfaced correctly. Did you use AI tools to help write this code? partial
110 lines
3.5 KiB
C++
110 lines
3.5 KiB
C++
#pragma once
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "FontInstaller.h"
|
|
#include "SdCardFont.h"
|
|
#include "activities/Activity.h"
|
|
#include "util/ButtonNavigator.h"
|
|
|
|
// JSON schema version of the fonts.json manifest. The canonical version for
|
|
// the build tooling lives in lib/EpdFont/scripts/cpfont_version.py. This
|
|
// firmware-side copy must be bumped manually when the firmware is updated to
|
|
// support a new manifest schema.
|
|
#define FONTS_MANIFEST_VERSION 1
|
|
|
|
#ifndef FONT_MANIFEST_URL
|
|
// Manifest + .cpfont assets are published by .github/workflows/release-fonts.yml
|
|
// to the crosspoint-fonts repo under the "sd-fonts-m<META>-b<BIN>" tag. The tag
|
|
// pattern must stay in sync with the workflow; it derives its version numbers
|
|
// from lib/EpdFont/scripts/cpfont_version.py.
|
|
#define FONT_MANIFEST_URL_STRINGIFY_INNER(x) #x
|
|
#define FONT_MANIFEST_URL_STRINGIFY(x) FONT_MANIFEST_URL_STRINGIFY_INNER(x)
|
|
#define FONT_MANIFEST_URL \
|
|
"https://github.com/crosspoint-reader/crosspoint-fonts/releases/download/sd-fonts-m" FONT_MANIFEST_URL_STRINGIFY( \
|
|
FONTS_MANIFEST_VERSION) "-b" FONT_MANIFEST_URL_STRINGIFY(CPFONT_VERSION) "/fonts.json"
|
|
#endif
|
|
|
|
class FontDownloadActivity : public Activity {
|
|
public:
|
|
explicit FontDownloadActivity(GfxRenderer& renderer, MappedInputManager& mappedInput);
|
|
|
|
void onEnter() override;
|
|
void onExit() override;
|
|
void loop() override;
|
|
void render(RenderLock&&) override;
|
|
bool preventAutoSleep() override {
|
|
return state_ == LOADING_MANIFEST || state_ == DOWNLOADING ||
|
|
// The download is synchronous and blocks the main loop until it
|
|
// completes, so activityManager.preventAutoSleep() is never polled
|
|
// during downloading.
|
|
state_ == COMPLETE || state_ == ERROR;
|
|
}
|
|
bool skipLoopDelay() override { return true; }
|
|
|
|
private:
|
|
enum State {
|
|
WIFI_SELECTION,
|
|
LOADING_MANIFEST,
|
|
FAMILY_LIST,
|
|
DOWNLOADING,
|
|
COMPLETE,
|
|
ERROR,
|
|
};
|
|
|
|
struct ManifestFile {
|
|
std::string name;
|
|
size_t size = 0;
|
|
uint32_t crc32 = 0;
|
|
};
|
|
|
|
struct ManifestFamily {
|
|
std::string name;
|
|
std::string description;
|
|
std::vector<std::string> styles;
|
|
std::vector<ManifestFile> files;
|
|
size_t totalSize = 0;
|
|
bool installed = false;
|
|
bool hasUpdate = false;
|
|
};
|
|
|
|
State state_ = WIFI_SELECTION;
|
|
FontInstaller fontInstaller_;
|
|
ButtonNavigator buttonNavigator_;
|
|
|
|
// Manifest data
|
|
std::string baseUrl_;
|
|
std::vector<ManifestFamily> families_;
|
|
int selectedIndex_ = 0;
|
|
|
|
// Download progress
|
|
size_t currentFileIndex_ = 0;
|
|
size_t currentFileTotal_ = 0;
|
|
size_t fileProgress_ = 0;
|
|
size_t fileTotal_ = 0;
|
|
int downloadingFamilyIndex_ = 0;
|
|
std::string errorMessage_;
|
|
bool cancelRequested_ = false;
|
|
|
|
void onWifiSelectionComplete(bool success);
|
|
bool fetchAndParseManifest();
|
|
void downloadFamily(ManifestFamily& family);
|
|
void downloadAll();
|
|
void updateAll();
|
|
static bool computeFileCrc32(const char* path, uint32_t& outCrc);
|
|
bool showDownloadAllRow() const;
|
|
bool showUpdateAllRow() const;
|
|
int specialRowCount() const;
|
|
bool isDownloadAllRow(int index) const;
|
|
bool isUpdateAllRow(int index) const;
|
|
bool isSelectedFamilyDeletable() const;
|
|
void promptDeleteSelectedFamily();
|
|
void onDeleteConfirmationResult(const ActivityResult& result);
|
|
int familyIndexFromList(int listIndex) const { return listIndex - specialRowCount(); }
|
|
int listItemCount() const;
|
|
size_t totalDownloadSize() const;
|
|
size_t totalUpdateSize() const;
|
|
static std::string formatSize(size_t bytes);
|
|
};
|