Skip to content
This repository was archived by the owner on Jan 21, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This fork is based on https://github.com/yubox-node-org/ESPAsyncWebServer and in
- Deployed in PlatformIO registry and Arduino IDE library manager
- CI
- Only supports ESP32
- Resurrected `AsyncWebSocketMessageBuffer` and `makeBuffer()` in order to make the fork API-compatible with the original library from me-no-dev regarding WebSocket.

## Documentation

Expand All @@ -23,13 +24,29 @@ Please look at the original libraries for more examples and documentation.

[https://github.com/yubox-node-org/ESPAsyncWebServer](https://github.com/yubox-node-org/ESPAsyncWebServer)

## Pitfalls
## `AsyncWebSocketMessageBuffer` and `makeBuffer()`

The fork from yubox introduces some breaking API changes compared to the original library, especially regarding the use of `std::shared_ptr<std::vector<uint8_t>>` for WebSocket.
Thanks to this fork, you can handle them by using `ASYNCWEBSERVER_FORK_mathieucarbou`.
The fork from `yubox-node-org` introduces some breaking API changes compared to the original library, especially regarding the use of `std::shared_ptr<std::vector<uint8_t>>` for WebSocket.

Here is an example for serializing a Json document in a websocket message buffer directly.
This code is compatible with both forks.
This fork is compatible with the original library from `me-no-dev` regarding WebSocket, and wraps the optimizations done by `yubox-node-org` in the `AsyncWebSocketMessageBuffer` class.
So you have the choice of which API to use.
I strongly suggest to use the optimized API from `yubox-node-org` as it is much more efficient.

Here is an example for serializing a Json document in a websocket message buffer. This code is compatible with any forks, but not optimized:

```cpp
void send(JsonDocument& doc) {
const size_t len = measureJson(doc);

// original API from me-no-dev
AsyncWebSocketMessageBuffer* buffer = _ws->makeBuffer(len);
assert(buffer); // up to you to keep or remove this
serializeJson(doc, buffer->get(), len);
_ws->textAll(buffer);
}
```

Here is an example for serializing a Json document in a more optimized way, and compatible with both forks:

```cpp
void send(JsonDocument& doc) {
Expand Down
81 changes: 74 additions & 7 deletions src/AsyncWebSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,39 @@ size_t webSocketSendFrame(AsyncClient *client, bool final, uint8_t opcode, bool



/*
* AsyncWebSocketMessageBuffer
*/

AsyncWebSocketMessageBuffer::AsyncWebSocketMessageBuffer()
: _buffer(std::make_shared<std::vector<uint8_t>>(0))
{
}

AsyncWebSocketMessageBuffer::AsyncWebSocketMessageBuffer(uint8_t* data, size_t size)
: _buffer(std::make_shared<std::vector<uint8_t>>(size))
{
std::memcpy(_buffer->data(), data, size);
}

AsyncWebSocketMessageBuffer::AsyncWebSocketMessageBuffer(size_t size)
: _buffer(std::make_shared<std::vector<uint8_t>>(size))
{
}

AsyncWebSocketMessageBuffer::~AsyncWebSocketMessageBuffer()
{
_buffer.reset();
}

bool AsyncWebSocketMessageBuffer::reserve(size_t size)
{
if (_buffer->capacity() >= size)
return true;
_buffer->reserve(size);
return _buffer->capacity() >= size;
}

/*
* Control Frame
*/
Expand Down Expand Up @@ -644,22 +677,28 @@ size_t AsyncWebSocketClient::printf_P(PGM_P formatP, ...)
#endif

namespace {
std::shared_ptr<std::vector<uint8_t>> makeBuffer(const uint8_t *message, size_t len)
std::shared_ptr<std::vector<uint8_t>> makeSharedBuffer(const uint8_t *message, size_t len)
{
auto buffer = std::make_shared<std::vector<uint8_t>>(len);
std::memcpy(buffer->data(), message, len);
return buffer;
}
}

void AsyncWebSocketClient::text(AsyncWebSocketMessageBuffer * buffer)
{
text(std::move(buffer->_buffer));
delete buffer;
}

void AsyncWebSocketClient::text(std::shared_ptr<std::vector<uint8_t>> buffer)
{
_queueMessage(buffer);
}

void AsyncWebSocketClient::text(const uint8_t *message, size_t len)
{
text(makeBuffer(message, len));
text(makeSharedBuffer(message, len));
}

void AsyncWebSocketClient::text(const char *message, size_t len)
Expand Down Expand Up @@ -698,14 +737,20 @@ void AsyncWebSocketClient::text(const __FlashStringHelper *data)
}
}

void AsyncWebSocketClient::binary(AsyncWebSocketMessageBuffer * buffer)
{
binary(std::move(buffer->_buffer));
delete buffer;
}

void AsyncWebSocketClient::binary(std::shared_ptr<std::vector<uint8_t>> buffer)
{
_queueMessage(buffer, WS_BINARY);
}

void AsyncWebSocketClient::binary(const uint8_t *message, size_t len)
{
binary(makeBuffer(message, len));
binary(makeSharedBuffer(message, len));
}

void AsyncWebSocketClient::binary(const char *message, size_t len)
Expand Down Expand Up @@ -853,7 +898,7 @@ void AsyncWebSocket::pingAll(const uint8_t *data, size_t len)
void AsyncWebSocket::text(uint32_t id, const uint8_t *message, size_t len)
{
if (AsyncWebSocketClient * c = client(id))
c->text(makeBuffer(message, len));
c->text(makeSharedBuffer(message, len));
}
void AsyncWebSocket::text(uint32_t id, const char *message, size_t len)
{
Expand Down Expand Up @@ -889,6 +934,12 @@ void AsyncWebSocket::text(uint32_t id, const __FlashStringHelper *data)
}
}

void AsyncWebSocket::textAll(AsyncWebSocketMessageBuffer * buffer)
{
textAll(std::move(buffer->_buffer));
delete buffer;
}

void AsyncWebSocket::textAll(std::shared_ptr<std::vector<uint8_t>> buffer)
{
for (auto &c : _clients)
Expand All @@ -897,7 +948,7 @@ void AsyncWebSocket::textAll(std::shared_ptr<std::vector<uint8_t>> buffer)
}
void AsyncWebSocket::textAll(const uint8_t *message, size_t len)
{
textAll(makeBuffer(message, len));
textAll(makeSharedBuffer(message, len));
}
void AsyncWebSocket::textAll(const char * message, size_t len)
{
Expand Down Expand Up @@ -935,7 +986,7 @@ void AsyncWebSocket::textAll(const __FlashStringHelper *data)
void AsyncWebSocket::binary(uint32_t id, const uint8_t *message, size_t len)
{
if (AsyncWebSocketClient *c = client(id))
c->binary(makeBuffer(message, len));
c->binary(makeSharedBuffer(message, len));
}
void AsyncWebSocket::binary(uint32_t id, const char * message, size_t len)
{
Expand All @@ -961,6 +1012,12 @@ void AsyncWebSocket::binary(uint32_t id, const __FlashStringHelper *data, size_t
}
}

void AsyncWebSocket::binaryAll(AsyncWebSocketMessageBuffer * buffer)
{
binaryAll(std::move(buffer->_buffer));
delete buffer;
}

void AsyncWebSocket::binaryAll(std::shared_ptr<std::vector<uint8_t>> buffer)
{
for (auto &c : _clients)
Expand All @@ -970,7 +1027,7 @@ void AsyncWebSocket::binaryAll(std::shared_ptr<std::vector<uint8_t>> buffer)

void AsyncWebSocket::binaryAll(const uint8_t *message, size_t len)
{
binaryAll(makeBuffer(message, len));
binaryAll(makeSharedBuffer(message, len));
}

void AsyncWebSocket::binaryAll(const char *message, size_t len)
Expand Down Expand Up @@ -1141,6 +1198,16 @@ void AsyncWebSocket::handleRequest(AsyncWebServerRequest *request)
request->send(response);
}

AsyncWebSocketMessageBuffer * AsyncWebSocket::makeBuffer(size_t size)
{
return new AsyncWebSocketMessageBuffer(size);
}

AsyncWebSocketMessageBuffer * AsyncWebSocket::makeBuffer(uint8_t * data, size_t size)
{
return new AsyncWebSocketMessageBuffer(data, size);
}

/*
* Response to Web Socket request - sends the authorization and detaches the TCP Client from the web server
* Authentication code from https://github.com/Links2004/arduinoWebSockets/blob/master/src/WebSockets.cpp#L480
Expand Down
26 changes: 26 additions & 0 deletions src/AsyncWebSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,23 @@ typedef enum { WS_CONTINUATION, WS_TEXT, WS_BINARY, WS_DISCONNECT = 0x08, WS_PIN
typedef enum { WS_MSG_SENDING, WS_MSG_SENT, WS_MSG_ERROR } AwsMessageStatus;
typedef enum { WS_EVT_CONNECT, WS_EVT_DISCONNECT, WS_EVT_PONG, WS_EVT_ERROR, WS_EVT_DATA } AwsEventType;

class AsyncWebSocketMessageBuffer {
friend AsyncWebSocket;
friend AsyncWebSocketClient;

private:
std::shared_ptr<std::vector<uint8_t>> _buffer;

public:
AsyncWebSocketMessageBuffer();
AsyncWebSocketMessageBuffer(size_t size);
AsyncWebSocketMessageBuffer(uint8_t* data, size_t size);
~AsyncWebSocketMessageBuffer();
bool reserve(size_t size);
uint8_t* get() { return _buffer->data(); }
size_t length() const { return _buffer->size(); }
};

class AsyncWebSocketMessage
{
private:
Expand Down Expand Up @@ -180,13 +197,15 @@ class AsyncWebSocketClient {
void text(const char *message);
void text(const String &message);
void text(const __FlashStringHelper *message);
void text(AsyncWebSocketMessageBuffer *buffer);

void binary(std::shared_ptr<std::vector<uint8_t>> buffer);
void binary(const uint8_t *message, size_t len);
void binary(const char * message, size_t len);
void binary(const char * message);
void binary(const String &message);
void binary(const __FlashStringHelper *message, size_t len);
void binary(AsyncWebSocketMessageBuffer *buffer);

bool canSend() const;

Expand Down Expand Up @@ -245,6 +264,7 @@ class AsyncWebSocket: public AsyncWebHandler {
void textAll(const char * message);
void textAll(const String &message);
void textAll(const __FlashStringHelper *message); // need to convert
void textAll(AsyncWebSocketMessageBuffer *buffer);

void binary(uint32_t id, const uint8_t *message, size_t len);
void binary(uint32_t id, const char *message, size_t len);
Expand All @@ -258,6 +278,7 @@ class AsyncWebSocket: public AsyncWebHandler {
void binaryAll(const char *message);
void binaryAll(const String &message);
void binaryAll(const __FlashStringHelper *message, size_t len);
void binaryAll(AsyncWebSocketMessageBuffer *buffer);

size_t printf(uint32_t id, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
size_t printfAll(const char *format, ...) __attribute__ ((format (printf, 2, 3)));
Expand All @@ -283,6 +304,11 @@ class AsyncWebSocket: public AsyncWebHandler {
virtual bool canHandle(AsyncWebServerRequest *request) override final;
virtual void handleRequest(AsyncWebServerRequest *request) override final;


// messagebuffer functions/objects.
AsyncWebSocketMessageBuffer * makeBuffer(size_t size = 0);
AsyncWebSocketMessageBuffer * makeBuffer(uint8_t * data, size_t size);

const std::list<AsyncWebSocketClient> &getClients() const { return _clients; }
};

Expand Down