Skip to content

Commit c722ab0

Browse files
committed
Fix RealtimeDatabase issue #206
1 parent bc1e8af commit c722ab0

8 files changed

Lines changed: 114 additions & 59 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/mobizt/FirebaseClient/.github%2Fworkflows%2Fcompile_library.yml?logo=github&label=compile) [![Github Stars](https://img.shields.io/github/stars/mobizt/FirebaseClient?logo=github)](https://github.com/mobizt/FirebaseClient/stargazers) ![Github Issues](https://img.shields.io/github/issues/mobizt/FirebaseClient?logo=github)
44

5-
![GitHub Release](https://img.shields.io/github/v/release/mobizt/FirebaseClient) ![Arduino](https://img.shields.io/badge/Arduino-v1.4.18-57C207?logo=arduino) ![PlatformIO](https://badges.registry.platformio.org/packages/mobizt/library/FirebaseClient.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/mobizt/FirebaseClient)
5+
![GitHub Release](https://img.shields.io/github/v/release/mobizt/FirebaseClient) ![Arduino](https://img.shields.io/badge/Arduino-v1.5.0-57C207?logo=arduino) ![PlatformIO](https://badges.registry.platformio.org/packages/mobizt/library/FirebaseClient.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/mobizt/FirebaseClient)
66

77
[![GitHub Sponsors](https://img.shields.io/github/sponsors/mobizt?logo=github)](https://github.com/sponsors/mobizt)
88

9-
Revision `2025-01-13T05:09:36Z`
9+
Revision `2025-01-17T14:42:44Z`
1010

1111
## Table of Contents
1212

library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "FirebaseClient",
3-
"version": "1.4.18",
3+
"version": "1.5.0",
44
"keywords": "communication, REST, esp32, esp8266, arduino",
55
"description": "Async Firebase Client library for Arduino.",
66
"repository": {

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name=FirebaseClient
22

3-
version=1.4.18
3+
version=1.5.0
44

55
author=Mobizt
66

resources/docs/async_result.md

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,19 @@ Get the copy of server response payload string.
2929
String payload() const
3030
```
3131

32+
3. ## 🔹 size_t length() const
33+
34+
Get the length of response payload string.
35+
36+
```cpp
37+
size_t length() const
38+
```
39+
3240
**Returns:**
3341

3442
- `String` - The copy of payload string.
3543

36-
3. ## 🔹 String path() const
44+
4. ## 🔹 String path() const
3745

3846
Get the path of the resource of the request.
3947

@@ -46,7 +54,7 @@ String path() const
4654
- `String` - The path of the resource of the request.
4755

4856

49-
4. ## 🔹 String etag() const
57+
5. ## 🔹 String etag() const
5058

5159
Get the Etag of the server response headers.
5260

@@ -59,7 +67,7 @@ String etag() const
5967
- `String` - The ETag of response header.
6068

6169

62-
5. ## 🔹 String uid() const
70+
6. ## 🔹 String uid() const
6371

6472
Get the unique identifier of async task.
6573

@@ -72,7 +80,7 @@ String uid() const
7280
- `String` - The UID of async task.
7381

7482

75-
6. ## 🔹 String debug()
83+
7. ## 🔹 String debug()
7684

7785
Get the debug information.
7886

@@ -84,15 +92,15 @@ String debug()
8492

8593
- `String` - The debug information.
8694

87-
7. ## 🔹 void clear()
95+
8. ## 🔹 void clear()
8896

8997
Clear the async result.
9098

9199
```cpp
92100
void clear()
93101
```
94102

95-
8. ## 🔹 RealtimeDatabaseResult &to()
103+
9. ## 🔹 RealtimeDatabaseResult &to()
96104

97105
Get the reference to the internal RealtimeDatabaseResult object.
98106

@@ -105,7 +113,7 @@ RealtimeDatabaseResult &to()
105113
- `RealtimeDatabaseResult &` - The reference to the internal RealtimeDatabaseResult object.
106114

107115

108-
9. ## 🔹 int available()
116+
10. ## 🔹 int available()
109117

110118
Get the number of bytes of available response payload.
111119

@@ -118,7 +126,7 @@ int available()
118126
- `int` - The number of bytes available.
119127

120128

121-
10. ## 🔹 app_event_t &appEvent()
129+
11. ## 🔹 app_event_t &appEvent()
122130

123131
Get the reference of internal app event information.
124132

@@ -131,7 +139,7 @@ app_event_t &appEvent()
131139
- `app_event_t &` - The reference of internal app event.
132140

133141

134-
11. ## 🔹 bool uploadProgress()
142+
12. ## 🔹 bool uploadProgress()
135143

136144
Check if file/BLOB upload information is available.
137145

@@ -144,7 +152,7 @@ bool uploadProgress()
144152
- `bool` - Returns true if upload information is available.
145153

146154

147-
12. ## 🔹 upload_data_t uploadInfo() const
155+
13. ## 🔹 upload_data_t uploadInfo() const
148156

149157
Get the file/BLOB upload information.
150158

@@ -157,7 +165,7 @@ upload_data_t uploadInfo() const
157165
- `upload_data_t` - The file/BLOB upload information.
158166

159167

160-
13. ## 🔹 bool downloadProgress()
168+
14. ## 🔹 bool downloadProgress()
161169

162170
Check if the file/BLOB download information is availablle.
163171

@@ -170,7 +178,7 @@ bool downloadProgress()
170178
- `bool` - Returns true if download information is available.
171179

172180

173-
14. ## 🔹 download_data_t downloadInfo() const
181+
15. ## 🔹 download_data_t downloadInfo() const
174182

175183
Get the file/BLOB download information.
176184

@@ -183,7 +191,7 @@ download_data_t downloadInfo() const
183191
- `download_data_t` - The file/BLOB download information.
184192

185193

186-
15. ## 🔹 bool isOTA() const
194+
16. ## 🔹 bool isOTA() const
187195

188196
Check if the result is from OTA download task.
189197

@@ -196,7 +204,7 @@ bool isOTA() const
196204
- `bool` - Returns true if the result is from OTA download task.
197205

198206

199-
16. ## 🔹 bool isError()
207+
17. ## 🔹 bool isError()
200208

201209
Check if the error occurred in async task.
202210

@@ -209,7 +217,7 @@ bool isError()
209217
- `bool` - Returns true if error occurred.
210218

211219

212-
17. ## 🔹 bool isDebug()
220+
18. ## 🔹 bool isDebug()
213221

214222
Check if the debug information in available.
215223

@@ -222,7 +230,7 @@ bool isDebug()
222230
- `bool` - Returns true if debug information in available.
223231

224232

225-
18. ## 🔹 bool isEvent()
233+
19. ## 🔹 bool isEvent()
226234

227235
Check if the app event information in available.
228236

@@ -235,7 +243,7 @@ bool isEvent()
235243
- `bool` - Returns true if app event information in available.
236244

237245

238-
19. ## 🔹 FirebaseError &error()
246+
20. ## 🔹 FirebaseError &error()
239247

240248
Get the reference of internal FirebaseError object.
241249

src/core/AsyncClient/AsyncClient.h

Lines changed: 66 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Created January 14, 2025
2+
* Created January 17, 2025
33
*
44
* For MCU build target (CORE_ARDUINO_XXXX), see Options.h.
55
*
@@ -858,11 +858,14 @@ class AsyncClientClass : public ResultBase, RTDBResultBase
858858
if (!readPayload(sData))
859859
return false;
860860

861+
String *payload = &sData->response.val[res_hndlr_ns::payload];
862+
861863
if (sData->response.flags.sse || !sData->response.flags.payload_remaining)
862864
{
863865
if (!sData->auth_used)
864866
{
865-
sData->aResult.setPayload(sData->response.val[res_hndlr_ns::payload]);
867+
if (!sData->response.flags.sse)
868+
sData->aResult.setPayload(*payload);
866869

867870
if (sData->aResult.download_data.total > 0)
868871
clearAppData(sData->aResult.app_data);
@@ -872,37 +875,43 @@ class AsyncClientClass : public ResultBase, RTDBResultBase
872875
if (sData->request.method == async_request_handler_t::http_post)
873876
parseNodeName(&sData->aResult.rtdbResult);
874877

875-
// data available from sse event
876-
if (sData->response.flags.sse && sData->response.val[res_hndlr_ns::payload].length())
878+
// Data available from sse event
879+
if (sData->response.flags.sse && payload->length())
877880
{
878-
// order of checking: event, data, newline
879-
if (sData->response.val[res_hndlr_ns::payload].indexOf("event: ") > -1 && sData->response.val[res_hndlr_ns::payload].indexOf("data: ") > -1 && sData->response.val[res_hndlr_ns::payload].indexOf("\n") > -1)
881+
882+
if (payload->indexOf("event: ") > -1 && payload->indexOf("data: ") > -1 && payload->indexOf("\n") > -1)
880883
{
884+
// Prevent sse timeout due to large sse Stream playload
885+
feedSSETimer(&sData->aResult.rtdbResult);
881886

882-
parseSSE(&sData->aResult.rtdbResult);
883-
884-
// Event filtering.
885-
String event = sData->aResult.rtdbResult.event();
886-
if (sse_events_filter.length() == 0 ||
887-
(sData->response.flags.http_response && sse_events_filter.indexOf("get") > -1 && event.indexOf("put") > -1) ||
888-
(!sData->response.flags.http_response && sse_events_filter.indexOf("put") > -1 && event.indexOf("put") > -1) ||
889-
(sse_events_filter.indexOf("patch") > -1 && event.indexOf("patch") > -1) ||
890-
(sse_events_filter.indexOf("keep-alive") > -1 && event.indexOf("keep-alive") > -1) ||
891-
(sse_events_filter.indexOf("cancel") > -1 && event.indexOf("cancel") > -1) ||
892-
(sse_events_filter.indexOf("auth_revoked") > -1 && event.indexOf("auth_revoked") > -1))
893-
{
894-
// save payload to slot result
895-
sData->aResult.setPayload(sData->response.val[res_hndlr_ns::payload]);
896-
clear(sData->response.val[res_hndlr_ns::payload]);
897-
sData->response.flags.payload_available = true;
898-
returnResult(sData, true);
899-
}
900-
else
887+
if ((*payload)[payload->length() - 1] == '\n' && sData->response.tcpAvailable(client_type, client, async_tcp_config) == 0)
901888
{
902-
clear(sData->response.val[res_hndlr_ns::payload]);
903-
}
889+
setRefPayload(&sData->aResult.rtdbResult, payload);
890+
parseSSE(&sData->aResult.rtdbResult);
891+
892+
// Event filtering.
893+
String event = sData->aResult.rtdbResult.event();
894+
if (sse_events_filter.length() == 0 ||
895+
(sData->response.flags.http_response && sse_events_filter.indexOf("get") > -1 && event.indexOf("put") > -1) ||
896+
(!sData->response.flags.http_response && sse_events_filter.indexOf("put") > -1 && event.indexOf("put") > -1) ||
897+
(sse_events_filter.indexOf("patch") > -1 && event.indexOf("patch") > -1) ||
898+
(sse_events_filter.indexOf("keep-alive") > -1 && event.indexOf("keep-alive") > -1) ||
899+
(sse_events_filter.indexOf("cancel") > -1 && event.indexOf("cancel") > -1) ||
900+
(sse_events_filter.indexOf("auth_revoked") > -1 && event.indexOf("auth_revoked") > -1))
901+
{
902+
// save payload to slot result
903+
sData->aResult.setPayload(*payload);
904+
clear(*payload);
905+
sData->response.flags.payload_available = true;
906+
returnResult(sData, true);
907+
}
908+
else
909+
{
910+
clear(*payload);
911+
}
904912

905-
sData->response.flags.http_response = false;
913+
sData->response.flags.http_response = false;
914+
}
906915
}
907916
}
908917
#endif
@@ -1142,7 +1151,16 @@ class AsyncClientClass : public ResultBase, RTDBResultBase
11421151

11431152
if (sData->response.flags.chunks)
11441153
{
1145-
if (decodeChunks(sData, client, &sData->response.val[res_hndlr_ns::payload]) == -1)
1154+
// Use temporary String buffer for decodeChunks
1155+
String temp;
1156+
int res = decodeChunks(sData, client, &temp);
1157+
if (temp.length())
1158+
{
1159+
reserveString(sData);
1160+
sData->response.val[res_hndlr_ns::payload] += temp;
1161+
}
1162+
1163+
if (res == -1)
11461164
sData->response.flags.payload_remaining = false;
11471165
}
11481166
else
@@ -1294,7 +1312,14 @@ class AsyncClientClass : public ResultBase, RTDBResultBase
12941312
}
12951313
}
12961314
else
1297-
sData->response.payloadRead += readLine(sData, sData->response.val[res_hndlr_ns::payload]);
1315+
{
1316+
// Use temporary String buffer for readLine
1317+
String temp;
1318+
size_t len = readLine(sData, temp);
1319+
sData->response.payloadRead += len;
1320+
reserveString(sData);
1321+
sData->response.val[res_hndlr_ns::payload] += temp;
1322+
}
12981323
}
12991324
}
13001325
}
@@ -1354,6 +1379,17 @@ class AsyncClientClass : public ResultBase, RTDBResultBase
13541379
return sData->error.code == 0;
13551380
}
13561381

1382+
void reserveString(async_data_item_t *sData)
1383+
{
1384+
// String memory reservation is needed to hadle large data in external memory.
1385+
#if defined(ENABLE_PSRAM) && ((defined(ESP8266) && defined(MMU_EXTERNAL_HEAP)) || (defined(ESP32) && defined(BOARD_HAS_PSRAM)))
1386+
String old = sData->response.val[res_hndlr_ns::payload];
1387+
sData->response.val[res_hndlr_ns::payload].remove(0, sData->response.val[res_hndlr_ns::payload].length());
1388+
sData->response.val[res_hndlr_ns::payload].reserve(sData->response.payloadRead + 1);
1389+
sData->response.val[res_hndlr_ns::payload] = old;
1390+
#endif
1391+
}
1392+
13571393
// non-block memory buffer for collecting the multiple of 4 data prepared for base64 decoding
13581394
uint8_t *asyncBase64Buffer(async_data_item_t *sData, Memory &mem, int &toRead, int &read)
13591395
{

src/core/AsyncResult/AsyncResult.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Created December 27, 2024
2+
* Created January 17, 2025
33
*
44
* The MIT License (MIT)
55
* Copyright (c) 2025 K. Suwatchai (Mobizt)
@@ -228,6 +228,13 @@ class AsyncResult : public ResultBase, RealtimeDatabaseResult
228228
*/
229229
String payload() const { return val[ares_ns::data_payload].c_str(); }
230230

231+
/**
232+
* Get the length of response payload string.
233+
*
234+
* @return The payload string length.
235+
*/
236+
size_t length() const { return val[ares_ns::data_payload].length(); }
237+
231238
/**
232239
* Get the path of the resource of the request.
233240
*

0 commit comments

Comments
 (0)