Subversion Repositories ESP8266_P1_Meter

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 raymond 1
// SPDX-License-Identifier: LGPL-3.0-or-later
2
// Copyright 2016-2026 Hristo Gochkov, Mathieu Carbou, Emil Muratov, Will Miles
3
 
4
#pragma once
5
 
6
#ifdef Arduino_h
7
// arduino is not compatible with std::vector
8
#undef min
9
#undef max
10
#endif
11
#include <cbuf.h>
12
 
13
#include <memory>
14
#include <vector>
15
 
16
#include "./literals.h"
17
 
18
#ifndef CONFIG_LWIP_TCP_MSS
19
#ifdef TCP_MSS  // ESP8266
20
#define CONFIG_LWIP_TCP_MSS TCP_MSS
21
#else
22
// as it is defined for ESP32's Arduino LWIP
23
#define CONFIG_LWIP_TCP_MSS 1436
24
#endif
25
#endif
26
 
27
#define ASYNC_RESPONCE_BUFF_SIZE CONFIG_LWIP_TCP_MSS * 2
28
// It is possible to restore these defines, but one can use _min and _max instead. Or std::min, std::max.
29
 
30
class AsyncBasicResponse : public AsyncWebServerResponse {
31
private:
32
  String _content;
33
  // buffer to accumulate all response headers
34
  String _assembled_headers;
35
  // amount of headers buffer writtent to sockbuff
36
  size_t _writtenHeadersLength{0};
37
 
38
public:
39
  explicit AsyncBasicResponse(int code, const char *contentType = asyncsrv::empty, const char *content = asyncsrv::empty);
40
  AsyncBasicResponse(int code, const String &contentType, const String &content = asyncsrv::emptyString)
41
    : AsyncBasicResponse(code, contentType.c_str(), content.c_str()) {}
42
  void _respond(AsyncWebServerRequest *request) final;
43
  size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time) final {
44
    return write_send_buffs(request, len, time);
45
  };
46
  bool _sourceValid() const final {
47
    return true;
48
  }
49
 
50
protected:
51
  /**
52
   * @brief write next portion of response data to send buffs
53
   * this method (re)fills tcp send buffers, it could be called either at will
54
   * or from a tcp_recv/tcp_poll callbacks from AsyncTCP
55
   *
56
   * @param request - used to access client object
57
   * @param len - size of acknowledged data from the remote side (TCP window update, not TCP ack!)
58
   * @param time - time passed between last sent and received packet
59
   * @return size_t amount of response data placed to TCP send buffs for delivery (defined by sdkconfig value CONFIG_LWIP_TCP_SND_BUF_DEFAULT)
60
   */
61
  size_t write_send_buffs(AsyncWebServerRequest *request, size_t len, uint32_t time);
62
};
63
 
64
class AsyncAbstractResponse : public AsyncWebServerResponse {
65
private:
66
#if ASYNCWEBSERVER_USE_CHUNK_INFLIGHT
67
  // amount of response data in-flight, i.e. sent, but not acked yet
68
  size_t _in_flight{0};
69
  // in-flight queue credits
70
  size_t _in_flight_credit{2};
71
#endif
72
  // buffer to accumulate all response headers
73
  String _assembled_headers;
74
  // amount of headers buffer writtent to sockbuff
75
  size_t _writtenHeadersLength{0};
76
  // Data is inserted into cache at begin().
77
  // This is inefficient with vector, but if we use some other container,
78
  // we won't be able to access it as contiguous array of bytes when reading from it,
79
  // so by gaining performance in one place, we'll lose it in another.
80
  std::vector<uint8_t> _cache;
81
  // intermediate buffer to copy outbound data to, also it will keep pending data between _send calls
82
  std::unique_ptr<std::array<uint8_t, ASYNC_RESPONCE_BUFF_SIZE> > _send_buffer;
83
  // buffer data size specifiers
84
  size_t _send_buffer_offset{0}, _send_buffer_len{0};
85
  size_t _readDataFromCacheOrContent(uint8_t *data, const size_t len);
86
  size_t _fillBufferAndProcessTemplates(uint8_t *buf, size_t maxLen);
87
 
88
protected:
89
  AwsTemplateProcessor _callback;
90
  /**
91
   * @brief write next portion of response data to send buffs
92
   * this method (re)fills tcp send buffers, it could be called either at will
93
   * or from a tcp_recv/tcp_poll callbacks from AsyncTCP
94
   *
95
   * @param request - used to access client object
96
   * @param len - size of acknowledged data from the remote side (TCP window update, not TCP ack!)
97
   * @param time - time passed between last sent and received packet
98
   * @return size_t amount of response data placed to TCP send buffs for delivery (defined by sdkconfig value CONFIG_LWIP_TCP_SND_BUF_DEFAULT)
99
   */
100
  size_t write_send_buffs(AsyncWebServerRequest *request, size_t len, uint32_t time);
101
 
102
public:
103
  AsyncAbstractResponse(AwsTemplateProcessor callback = nullptr);
104
  virtual ~AsyncAbstractResponse() {}
105
  void _respond(AsyncWebServerRequest *request) final;
106
  size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time) final {
107
    return write_send_buffs(request, len, time);
108
  };
109
  virtual bool _sourceValid() const {
110
    return false;
111
  }
112
  virtual size_t _fillBuffer(uint8_t *buf __attribute__((unused)), size_t maxLen __attribute__((unused))) {
113
    return 0;
114
  }
115
};
116
 
117
#ifndef TEMPLATE_PLACEHOLDER
118
#define TEMPLATE_PLACEHOLDER '%'
119
#endif
120
 
121
#define TEMPLATE_PARAM_NAME_LENGTH 32
122
class AsyncFileResponse : public AsyncAbstractResponse {
123
  using File = fs::File;
124
  using FS = fs::FS;
125
 
126
private:
127
  File _content;
128
  void _setContentTypeFromPath(const String &path);
129
 
130
public:
131
  AsyncFileResponse(FS &fs, const String &path, const char *contentType = asyncsrv::empty, bool download = false, AwsTemplateProcessor callback = nullptr);
132
  AsyncFileResponse(FS &fs, const String &path, const String &contentType, bool download = false, AwsTemplateProcessor callback = nullptr)
133
    : AsyncFileResponse(fs, path, contentType.c_str(), download, callback) {}
134
  AsyncFileResponse(
135
    File content, const String &path, const char *contentType = asyncsrv::empty, bool download = false, AwsTemplateProcessor callback = nullptr
136
  );
137
  AsyncFileResponse(File content, const String &path, const String &contentType, bool download = false, AwsTemplateProcessor callback = nullptr)
138
    : AsyncFileResponse(content, path, contentType.c_str(), download, callback) {}
139
  ~AsyncFileResponse() {
140
    _content.close();
141
  }
142
  bool _sourceValid() const final {
143
    return !!(_content);
144
  }
145
  size_t _fillBuffer(uint8_t *buf, size_t maxLen) final;
146
};
147
 
148
class AsyncStreamResponse : public AsyncAbstractResponse {
149
private:
150
  Stream *_content;
151
 
152
public:
153
  AsyncStreamResponse(Stream &stream, const char *contentType, size_t len, AwsTemplateProcessor callback = nullptr);
154
  AsyncStreamResponse(Stream &stream, const String &contentType, size_t len, AwsTemplateProcessor callback = nullptr)
155
    : AsyncStreamResponse(stream, contentType.c_str(), len, callback) {}
156
  bool _sourceValid() const final {
157
    return !!(_content);
158
  }
159
  size_t _fillBuffer(uint8_t *buf, size_t maxLen) final;
160
};
161
 
162
class AsyncCallbackResponse : public AsyncAbstractResponse {
163
private:
164
  AwsResponseFiller _content;
165
  size_t _filledLength;
166
 
167
public:
168
  AsyncCallbackResponse(const char *contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
169
  AsyncCallbackResponse(const String &contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr)
170
    : AsyncCallbackResponse(contentType.c_str(), len, callback, templateCallback) {}
171
  bool _sourceValid() const final {
172
    return !!(_content);
173
  }
174
  size_t _fillBuffer(uint8_t *buf, size_t maxLen) final;
175
};
176
 
177
class AsyncChunkedResponse : public AsyncAbstractResponse {
178
private:
179
  AwsResponseFiller _content;
180
  size_t _filledLength;
181
 
182
public:
183
  AsyncChunkedResponse(const char *contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
184
  AsyncChunkedResponse(const String &contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr)
185
    : AsyncChunkedResponse(contentType.c_str(), callback, templateCallback) {}
186
  bool _sourceValid() const final {
187
    return !!(_content);
188
  }
189
  size_t _fillBuffer(uint8_t *buf, size_t maxLen) final;
190
};
191
 
192
class AsyncProgmemResponse : public AsyncAbstractResponse {
193
private:
194
  const uint8_t *_content;
195
  // offset index (how much we've sent already)
196
  size_t _index;
197
 
198
public:
199
  AsyncProgmemResponse(int code, const char *contentType, const uint8_t *content, size_t len, AwsTemplateProcessor callback = nullptr);
200
  AsyncProgmemResponse(int code, const String &contentType, const uint8_t *content, size_t len, AwsTemplateProcessor callback = nullptr)
201
    : AsyncProgmemResponse(code, contentType.c_str(), content, len, callback) {}
202
  bool _sourceValid() const final {
203
    return true;
204
  }
205
  size_t _fillBuffer(uint8_t *buf, size_t maxLen) final;
206
};
207
 
208
class AsyncResponseStream : public AsyncAbstractResponse, public Print {
209
private:
210
  std::unique_ptr<cbuf> _content;
211
 
212
public:
213
  AsyncResponseStream(const char *contentType, size_t bufferSize);
214
  AsyncResponseStream(const String &contentType, size_t bufferSize) : AsyncResponseStream(contentType.c_str(), bufferSize) {}
215
  bool _sourceValid() const final {
216
    return (_state < RESPONSE_END);
217
  }
218
  size_t _fillBuffer(uint8_t *buf, size_t maxLen) final;
219
  size_t write(const uint8_t *data, size_t len);
220
  size_t write(uint8_t data);
221
  /**
222
   * @brief Returns the number of bytes available in the stream.
223
   */
224
  size_t available() const {
225
    return _content->available();
226
  }
227
  using Print::write;
228
};