-
Notifications
You must be signed in to change notification settings - Fork 121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
/rfid endpoint - Serve with chunked response #280
Changes from 1 commit
3e2b0f6
788d4ff
0d9c7b3
b080121
86fa4f4
871df02
403d2e5
9c3b512
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -457,6 +457,7 @@ void webserverStart(void) { | |||||||
|
||||||||
// RFID | ||||||||
wServer.on("/rfid", HTTP_GET, handleGetRFIDRequest); | ||||||||
wServer.addRewrite(new OneParamRewrite("/rfid/details", "/rfid?details=true")); | ||||||||
wServer.addHandler(new AsyncCallbackJsonWebHandler("/rfid", handlePostRFIDRequest)); | ||||||||
wServer.addRewrite(new OneParamRewrite("/rfid/{id}", "/rfid?id={id}")); | ||||||||
wServer.on("/rfid", HTTP_DELETE, handleDeleteRFIDRequest); | ||||||||
|
@@ -1692,35 +1693,44 @@ bool DumpNvsToArrayCallback(const char *key, void *data) { | |||||||
return true; | ||||||||
} | ||||||||
|
||||||||
static String tagIdToJsonStr(const char *key) { | ||||||||
StaticJsonDocument<512> doc; | ||||||||
JsonObject entry = doc.createNestedObject(key); | ||||||||
if (!tagIdToJSON(key, entry)) { | ||||||||
return ""; | ||||||||
static String tagIdToJsonStr(const char *key, const bool withDetails) { | ||||||||
if (withDetails) { | ||||||||
StaticJsonDocument<512> doc; | ||||||||
JsonObject entry = doc.createNestedObject(key); | ||||||||
if (!tagIdToJSON(key, entry)) { | ||||||||
return ""; | ||||||||
} | ||||||||
String serializedJsonString; | ||||||||
serializeJson(entry, serializedJsonString); | ||||||||
return serializedJsonString; | ||||||||
} else { | ||||||||
return "\"" + String(key) + "\""; | ||||||||
} | ||||||||
String serializedJsonString; | ||||||||
serializeJson(entry, serializedJsonString); | ||||||||
return serializedJsonString; | ||||||||
} | ||||||||
|
||||||||
uint16_t nvsIndex; | ||||||||
|
||||||||
// Handles rfid-assignments requests (GET) | ||||||||
// /rfid returns an array of tag-id keys | ||||||||
// /rfid/details returns an array of tag-ids and details. Optional GET param "id" to list only a single assignment. | ||||||||
static void handleGetRFIDRequest(AsyncWebServerRequest *request) { | ||||||||
|
||||||||
String tagId, json = ""; | ||||||||
String tagId = ""; | ||||||||
|
||||||||
if (request->hasParam("id")) { | ||||||||
tagId = request->getParam("id")->value(); | ||||||||
} | ||||||||
|
||||||||
if ((tagId != "") && gPrefsRfid.isKey(tagId.c_str())) { | ||||||||
// return single RFID entry | ||||||||
json = tagIdToJsonStr(tagId.c_str()); | ||||||||
String json = tagIdToJsonStr(tagId.c_str(), true); | ||||||||
request->send(200, "application/json", json); | ||||||||
return; | ||||||||
} | ||||||||
static std::vector<String> nvsKeys {}; | ||||||||
// get tag details or just an array of key names | ||||||||
bool withDetails = request->hasParam("details"); | ||||||||
|
||||||||
std::vector<String> nvsKeys {}; | ||||||||
static uint16_t nvsIndex; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment on line 1747.
Suggested change
|
||||||||
nvsKeys.clear(); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not needed since nvsKeys was just created (since it's not a static variable any more), so it's already empty.
Suggested change
|
||||||||
// Dumps all RFID-keys from NVS into key array | ||||||||
listNVSKeys("rfidTags", &nvsKeys, DumpNvsToArrayCallback); | ||||||||
|
@@ -1732,33 +1742,38 @@ static void handleGetRFIDRequest(AsyncWebServerRequest *request) { | |||||||
// construct chunked repsonse | ||||||||
nvsIndex = 0; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see 1747
Suggested change
|
||||||||
AsyncWebServerResponse *response = request->beginChunkedResponse("application/json", | ||||||||
[](uint8_t *buffer, size_t maxLen, size_t index) { | ||||||||
[nvsKeys = std::move(nvsKeys), withDetails](uint8_t *buffer, size_t maxLen, size_t index) { | ||||||||
maxLen = maxLen >> 1; // some sort of bug with actual size available, reduce the len | ||||||||
size_t len = 0; | ||||||||
static String json; | ||||||||
String json; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can move nvsIndex into the lambda here. Also nvsIndex should have the same type as std::vector::size().
Suggested change
|
||||||||
|
||||||||
if (nvsIndex == 0) { | ||||||||
// start, write first tag | ||||||||
json = tagIdToJsonStr(nvsKeys[nvsIndex].c_str()); | ||||||||
len += sprintf(((char *) buffer), "[%s", json.c_str()); | ||||||||
json = tagIdToJsonStr(nvsKeys[nvsIndex].c_str(), withDetails); | ||||||||
if (json.length() > maxLen) { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You check that, but 4 lines later you're writing json.length() + 1 bytes, so you should also check for json.length() + 1 available space |
||||||||
Log_Println("/rfid: Buffer too small", LOGLEVEL_ERROR); | ||||||||
return len; | ||||||||
} | ||||||||
len += snprintf(((char *) buffer), maxLen, "[%s", json.c_str()); | ||||||||
nvsIndex++; | ||||||||
} | ||||||||
while (nvsIndex < nvsKeys.size()) { | ||||||||
// write tags as long we have enough room | ||||||||
json = tagIdToJsonStr(nvsKeys[nvsIndex].c_str()); | ||||||||
json = tagIdToJsonStr(nvsKeys[nvsIndex].c_str(), withDetails); | ||||||||
if ((len + json.length()) > maxLen) { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same issue, check is for 1 byte too few because of the comma |
||||||||
break; | ||||||||
} | ||||||||
len += sprintf(((char *) buffer + len), ",%s", json.c_str()); | ||||||||
len += snprintf(((char *) buffer + len), maxLen, ",%s", json.c_str()); | ||||||||
nvsIndex++; | ||||||||
} | ||||||||
if (nvsIndex == nvsKeys.size()) { | ||||||||
// finish | ||||||||
len += sprintf(((char *) buffer + len), "]"); | ||||||||
len += snprintf(((char *) buffer + len), maxLen, "]"); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That byte is written without a length check at all. |
||||||||
nvsIndex++; | ||||||||
} | ||||||||
return len; | ||||||||
}); | ||||||||
nvsKeys.clear(); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just saw, that we are accessing nvsKeys here. Since we called std::move on the variable, nvsKeys does not hold the array any more. As soons as the lambds is finished, the nvsKeys will go out of scope and it'll be destoryed.
Suggested change
|
||||||||
request->send(response); | ||||||||
} | ||||||||
|
||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OneParamRewrite is usually for path parameters in the form of /path/{some_param} -> /path?some_param={some_param} because AsyncWebServer cannot handle path params natively.
Does this even work and do something? Even if it does, using the "normal" AsyncWebRewrite makes more sense: https://github.com/me-no-dev/ESPAsyncWebServer#param-rewrite-with-matching
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it works fine, do you have a concrete improved code here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't test it, but just replacing 'OneParamRewrite' with 'AsyncWebRewrite' should do the same thing.