Fork of the excellent esp8266-react - https://github.com/rjwats/esp8266-react
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
4.9 KiB

  1. /**
  2. * A copy of AsyncJson.h from ESPAsyncWebServer, updated for ArduinoJson6.
  3. */
  4. #ifndef ASYNC_ARDUINO_JSON_6_H
  5. #define ASYNC_ARDUINO_JSON_6_H
  6. #include <ArduinoJson.h>
  7. #include <WebResponseImpl.h>
  8. #include <ESPAsyncWebServer.h>
  9. constexpr const char* JSON_MIMETYPE = "application/json";
  10. class ChunkPrint : public Print {
  11. private:
  12. uint8_t* _destination;
  13. size_t _to_skip;
  14. size_t _to_write;
  15. size_t _pos;
  16. public:
  17. ChunkPrint(uint8_t* destination, size_t from, size_t len)
  18. : _destination(destination), _to_skip(from), _to_write(len), _pos{0} {}
  19. virtual ~ChunkPrint(){}
  20. size_t write(uint8_t c){
  21. if (_to_skip > 0) {
  22. _to_skip--;
  23. return 1;
  24. } else if (_to_write > 0) {
  25. _to_write--;
  26. _destination[_pos++] = c;
  27. return 1;
  28. }
  29. return 0;
  30. }
  31. size_t write(const uint8_t *buffer, size_t size) {
  32. size_t written = 0;
  33. while (written < size && write(buffer[written])) {
  34. written++;
  35. }
  36. return written;
  37. }
  38. };
  39. class AsyncJsonResponse: public AsyncAbstractResponse {
  40. private:
  41. DynamicJsonDocument _jsonDocument;
  42. bool _isValid;
  43. JsonObject _root;
  44. public:
  45. AsyncJsonResponse(int maxSize): _jsonDocument(maxSize), _isValid{false} {
  46. _code = 200;
  47. _contentType = JSON_MIMETYPE;
  48. _root = _jsonDocument.to<JsonObject>();
  49. }
  50. ~AsyncJsonResponse() {}
  51. JsonObject getRoot() {
  52. return _root;
  53. }
  54. bool _sourceValid() const {
  55. return _isValid;
  56. }
  57. size_t setLength() {
  58. _contentLength = measureJson(_jsonDocument);
  59. if (_contentLength) { _isValid = true; }
  60. return _contentLength;
  61. }
  62. size_t getSize() {
  63. return _jsonDocument.size();
  64. }
  65. size_t _fillBuffer(uint8_t *data, size_t len){
  66. ChunkPrint dest(data, _sentLength, len);
  67. serializeJson(_jsonDocument, dest);
  68. return len;
  69. }
  70. };
  71. typedef std::function<void(AsyncWebServerRequest *request, JsonVariant json)> ArJsonRequestHandlerFunction;
  72. class AsyncCallbackJsonWebHandler: public AsyncWebHandler {
  73. private:
  74. protected:
  75. const String _uri;
  76. WebRequestMethodComposite _method;
  77. ArJsonRequestHandlerFunction _onRequest;
  78. size_t _contentLength;
  79. size_t _maxContentLength;
  80. public:
  81. AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest) : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
  82. void setMethod(WebRequestMethodComposite method){ _method = method; }
  83. void setMaxContentLength(int maxContentLength){ _maxContentLength = maxContentLength; }
  84. void onRequest(ArJsonRequestHandlerFunction fn){ _onRequest = fn; }
  85. virtual bool canHandle(AsyncWebServerRequest *request) override final{
  86. if(!_onRequest)
  87. return false;
  88. if(!(_method & request->method()))
  89. return false;
  90. if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/")))
  91. return false;
  92. if (!request->contentType().equalsIgnoreCase(JSON_MIMETYPE))
  93. return false;
  94. request->addInterestingHeader("ANY");
  95. return true;
  96. }
  97. virtual void handleRequest(AsyncWebServerRequest *request) override final {
  98. if(_onRequest) {
  99. if (request->_tempObject != nullptr) {
  100. DynamicJsonDocument _jsonDocument(_maxContentLength);
  101. DeserializationError err = deserializeJson(_jsonDocument, (uint8_t*)(request->_tempObject));
  102. if (err == DeserializationError::Ok) {
  103. _onRequest(request, _jsonDocument.as<JsonVariant>());
  104. return;
  105. }
  106. }
  107. request->send(_contentLength > _maxContentLength ? 413 : 400);
  108. } else {
  109. request->send(500);
  110. }
  111. }
  112. virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final {
  113. }
  114. virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final {
  115. if (_onRequest) {
  116. _contentLength = total;
  117. if (total > 0 && request->_tempObject == nullptr && total < _maxContentLength) {
  118. request->_tempObject = malloc(total);
  119. }
  120. if (request->_tempObject != nullptr) {
  121. memcpy((uint8_t*)(request->_tempObject) + index, data, len);
  122. }
  123. }
  124. }
  125. virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;}
  126. };
  127. /*
  128. * Listens for a response being destroyed and calls a callback during said distruction.
  129. *
  130. * Used so we can take action after the response has been rendered to the client.
  131. *
  132. * Avoids having to fork ESPAsyncWebServer with a callback feature - still not a nice use of a destructor!
  133. */
  134. typedef std::function<void()> AsyncJsonCallback;
  135. class AsyncJsonCallbackResponse: public AsyncJsonResponse {
  136. private:
  137. AsyncJsonCallback _callback;
  138. public:
  139. AsyncJsonCallbackResponse(AsyncJsonCallback callback, int maxSize) : AsyncJsonResponse(maxSize), _callback{callback} {}
  140. ~AsyncJsonCallbackResponse() {
  141. _callback();
  142. }
  143. };
  144. #endif