Skip to content

Commit 9f0cbaf

Browse files
Change from HTTPClient to WiFiClient (#113)
1 parent 4eefbe7 commit 9f0cbaf

File tree

4 files changed

+197
-46
lines changed

4 files changed

+197
-46
lines changed

src/OpenStreetMap-esp32.cpp

Lines changed: 8 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ void OpenStreetMap::updateCache(const tileList &requiredTiles, uint8_t zoom, Til
205205
if (!jobs.empty())
206206
{
207207
runJobs(jobs);
208-
log_d("Updated %i tiles in %lu ms - %i ms/tile", jobs.size(), millis() - startMS, (millis() - startMS) / jobs.size());
208+
log_i("Updated %i tiles in %lu ms - %i ms/tile", jobs.size(), millis() - startMS, (millis() - startMS) / jobs.size());
209209
}
210210
}
211211

@@ -250,7 +250,7 @@ void OpenStreetMap::makeJobList(const tileList &requiredTiles, std::vector<TileJ
250250

251251
void OpenStreetMap::runJobs(const std::vector<TileJob> &jobs)
252252
{
253-
log_d("submitting %i jobs", (int)jobs.size());
253+
log_i("submitting %i jobs", (int)jobs.size());
254254

255255
pendingJobs.store(jobs.size());
256256
for (const TileJob &job : jobs)
@@ -380,46 +380,9 @@ bool OpenStreetMap::fillBuffer(WiFiClient *stream, MemoryBuffer &buffer, size_t
380380
return true;
381381
}
382382

383-
std::unique_ptr<MemoryBuffer> OpenStreetMap::urlToBuffer(const char *url, String &result)
383+
std::unique_ptr<MemoryBuffer> OpenStreetMap::urlToBuffer(const char *url, String &result, ReusableTileFetcher &fetcher)
384384
{
385-
HTTPClientRAII http;
386-
if (!http.begin(url))
387-
{
388-
result = "Failed to initialize HTTP client";
389-
return nullptr;
390-
}
391-
392-
const int httpCode = http.GET();
393-
if (httpCode != HTTP_CODE_OK)
394-
{
395-
result = "HTTP Error: " + String(httpCode);
396-
return nullptr;
397-
}
398-
399-
const size_t contentSize = http.getSize();
400-
if (contentSize < 1)
401-
{
402-
result = "Empty or chunked response";
403-
return nullptr;
404-
}
405-
406-
WiFiClient *stream = http.getStreamPtr();
407-
if (!stream)
408-
{
409-
result = "Failed to get HTTP stream";
410-
return nullptr;
411-
}
412-
413-
auto buffer = std::make_unique<MemoryBuffer>(contentSize);
414-
if (!buffer->isAllocated())
415-
{
416-
result = "Failed to allocate buffer";
417-
return nullptr;
418-
}
419-
420-
if (!fillBuffer(stream, *buffer, contentSize, result))
421-
return nullptr;
422-
385+
auto buffer = fetcher.fetchToBuffer(url, result);
423386
return buffer;
424387
}
425388

@@ -429,7 +392,7 @@ void OpenStreetMap::PNGDraw(PNGDRAW *pDraw)
429392
getPNGCurrentCore()->getLineAsRGB565(pDraw, destRow, PNG_RGB565_BIG_ENDIAN, 0xffffffff);
430393
}
431394

432-
bool OpenStreetMap::fetchTile(CachedTile &tile, uint32_t x, uint32_t y, uint8_t zoom, String &result)
395+
bool OpenStreetMap::fetchTile(ReusableTileFetcher &fetcher, CachedTile &tile, uint32_t x, uint32_t y, uint8_t zoom, String &result)
433396
{
434397
String url = currentProvider->urlTemplate;
435398
url.replace("{x}", String(x));
@@ -438,7 +401,7 @@ bool OpenStreetMap::fetchTile(CachedTile &tile, uint32_t x, uint32_t y, uint8_t
438401
if (currentProvider->requiresApiKey && strstr(url.c_str(), "{apiKey}"))
439402
url.replace("{apiKey}", currentProvider->apiKey);
440403

441-
const std::unique_ptr<MemoryBuffer> buffer = urlToBuffer(url.c_str(), result);
404+
const std::unique_ptr<MemoryBuffer> buffer = urlToBuffer(url.c_str(), result, fetcher);
442405
if (!buffer)
443406
return false;
444407

@@ -476,6 +439,7 @@ bool OpenStreetMap::fetchTile(CachedTile &tile, uint32_t x, uint32_t y, uint8_t
476439
void OpenStreetMap::tileFetcherTask(void *param)
477440
{
478441
OpenStreetMap *osm = static_cast<OpenStreetMap *>(param);
442+
ReusableTileFetcher fetcher;
479443
while (true)
480444
{
481445
TileJob job;
@@ -486,7 +450,7 @@ void OpenStreetMap::tileFetcherTask(void *param)
486450
break;
487451

488452
String result;
489-
if (!osm->fetchTile(*job.tile, job.x, job.y, job.z, result))
453+
if (!osm->fetchTile(fetcher, *job.tile, job.x, job.y, job.z, result))
490454
{
491455
const size_t tileByteCount = osm->currentProvider->tileSize * osm->currentProvider->tileSize * 2;
492456
memset(job.tile->buffer, 0, tileByteCount);

src/OpenStreetMap-esp32.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "TileJob.hpp"
3838
#include "MemoryBuffer.hpp"
3939
#include "HTTPClientRAII.hpp"
40+
#include "ReusableTileFetcher.hpp"
4041
#include "fonts/DejaVu9-modded.h"
4142

4243
constexpr uint16_t OSM_BGCOLOR = lgfx::color565(32, 32, 128);
@@ -108,8 +109,8 @@ class OpenStreetMap
108109
void runJobs(const std::vector<TileJob> &jobs);
109110
CachedTile *findUnusedTile(const tileList &requiredTiles, uint8_t zoom);
110111
CachedTile *isTileCached(uint32_t x, uint32_t y, uint8_t z);
111-
bool fetchTile(CachedTile &tile, uint32_t x, uint32_t y, uint8_t zoom, String &result);
112-
std::unique_ptr<MemoryBuffer> urlToBuffer(const char *url, String &result);
112+
bool fetchTile(ReusableTileFetcher &fetcher, CachedTile &tile, uint32_t x, uint32_t y, uint8_t zoom, String &result);
113+
std::unique_ptr<MemoryBuffer> urlToBuffer(const char *url, String &result, ReusableTileFetcher &fetcher);
113114
bool fillBuffer(WiFiClient *stream, MemoryBuffer &buffer, size_t contentSize, String &result);
114115
bool composeMap(LGFX_Sprite &mapSprite, TileBufferList &tilePointers);
115116
static void tileFetcherTask(void *param);

src/ReusableTileFetcher.cpp

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#include "ReusableTileFetcher.hpp"
2+
3+
ReusableTileFetcher::ReusableTileFetcher() {}
4+
ReusableTileFetcher::~ReusableTileFetcher() { client.stop(); }
5+
6+
std::unique_ptr<MemoryBuffer> ReusableTileFetcher::fetchToBuffer(const String &url, String &result)
7+
{
8+
String host, path;
9+
uint16_t port;
10+
if (!parseUrl(url, host, path, port))
11+
{
12+
result = "Invalid URL";
13+
return nullptr;
14+
}
15+
16+
if (!ensureConnection(host, port, result))
17+
return nullptr;
18+
19+
if (!sendHttpRequest(host, path))
20+
{
21+
result = "Failed to send HTTP GET request";
22+
return nullptr;
23+
}
24+
25+
size_t contentLength = 0;
26+
if (!readHttpHeaders(contentLength, result))
27+
return nullptr;
28+
29+
auto buffer = std::make_unique<MemoryBuffer>(contentLength);
30+
if (!buffer->isAllocated())
31+
{
32+
result = "Buffer allocation failed";
33+
return nullptr;
34+
}
35+
36+
if (!readBody(*buffer, contentLength, result))
37+
return nullptr;
38+
39+
return buffer;
40+
}
41+
42+
bool ReusableTileFetcher::parseUrl(const String &url, String &host, String &path, uint16_t &port)
43+
{
44+
port = 80;
45+
46+
if (url.startsWith("https://"))
47+
{
48+
// Not supported in this fetcher (requires WiFiClientSecure)
49+
return false;
50+
}
51+
52+
if (!url.startsWith("http://"))
53+
return false;
54+
55+
int idxHostStart = 7; // length of "http://"
56+
int idxPath = url.indexOf('/', idxHostStart);
57+
if (idxPath == -1)
58+
return false;
59+
60+
host = url.substring(idxHostStart, idxPath);
61+
path = url.substring(idxPath);
62+
return true;
63+
}
64+
65+
bool ReusableTileFetcher::ensureConnection(const String &host, uint16_t port, String &result)
66+
{
67+
if (!client.connected() || host != currentHost || port != currentPort)
68+
{
69+
client.stop(); // Close old connection if mismatched
70+
if (!client.connect(host.c_str(), port))
71+
{
72+
result = "Connection failed to " + host;
73+
return false;
74+
}
75+
currentHost = host;
76+
currentPort = port;
77+
}
78+
return true;
79+
}
80+
81+
bool ReusableTileFetcher::sendHttpRequest(const String &host, const String &path)
82+
{
83+
client.print(String("GET ") + path + " HTTP/1.1\r\n");
84+
client.print(String("Host: ") + host + "\r\n");
85+
client.print("User-Agent: OpenStreetMap-esp32/1.0 (+https://github.com/CelliesProjects/OpenStreetMap-esp32)\r\n");
86+
client.print("Connection: keep-alive\r\n");
87+
client.print("\r\n");
88+
return true;
89+
}
90+
91+
bool ReusableTileFetcher::readHttpHeaders(size_t &contentLength, String &result)
92+
{
93+
String line;
94+
contentLength = 0;
95+
while (client.connected())
96+
{
97+
line = client.readStringUntil('\n');
98+
line.trim();
99+
if (line.length() == 0)
100+
break; // End of headers
101+
102+
if (line.startsWith("Content-Length:"))
103+
{
104+
contentLength = line.substring(15).toInt();
105+
}
106+
else if (line.startsWith("HTTP/1.1"))
107+
{
108+
if (!line.startsWith("HTTP/1.1 200"))
109+
{
110+
result = "HTTP error: " + line;
111+
return false;
112+
}
113+
}
114+
}
115+
116+
if (contentLength == 0)
117+
{
118+
result = "Missing or invalid Content-Length";
119+
return false;
120+
}
121+
122+
return true;
123+
}
124+
125+
bool ReusableTileFetcher::readBody(MemoryBuffer &buffer, size_t contentLength, String &result)
126+
{
127+
uint8_t *dest = buffer.get();
128+
size_t remaining = contentLength;
129+
size_t offset = 0;
130+
131+
unsigned long start = millis();
132+
while (remaining > 0 && millis() - start < 3000)
133+
{
134+
int len = client.read(dest + offset, remaining);
135+
if (len > 0)
136+
{
137+
remaining -= len;
138+
offset += len;
139+
}
140+
else if (len < 0)
141+
{
142+
result = "Read error";
143+
return false;
144+
}
145+
else
146+
{
147+
delay(1);
148+
}
149+
}
150+
151+
if (remaining > 0)
152+
{
153+
result = "Incomplete read";
154+
return false;
155+
}
156+
157+
return true;
158+
}

src/ReusableTileFetcher.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#pragma once
2+
3+
#include <WiFiClient.h>
4+
#include <memory>
5+
#include "MemoryBuffer.hpp" // your existing class
6+
7+
class ReusableTileFetcher {
8+
public:
9+
ReusableTileFetcher();
10+
~ReusableTileFetcher();
11+
12+
// Not copyable/movable
13+
ReusableTileFetcher(const ReusableTileFetcher &) = delete;
14+
ReusableTileFetcher &operator=(const ReusableTileFetcher &) = delete;
15+
16+
std::unique_ptr<MemoryBuffer> fetchToBuffer(const String &url, String &result);
17+
18+
private:
19+
WiFiClient client;
20+
String currentHost;
21+
uint16_t currentPort = 80;
22+
23+
bool parseUrl(const String &url, String &host, String &path, uint16_t &port);
24+
bool ensureConnection(const String &host, uint16_t port, String &result);
25+
bool sendHttpRequest(const String &host, const String &path);
26+
bool readHttpHeaders(size_t &contentLength, String &result);
27+
bool readBody(MemoryBuffer &buffer, size_t contentLength, String &result);
28+
};

0 commit comments

Comments
 (0)