Skip to content

Commit

Permalink
API Compatibility with AsyncWebSocketMessageBuffer and makeBuffer()
Browse files Browse the repository at this point in the history
  • Loading branch information
mathieucarbou committed Jan 25, 2024
1 parent 0d96aac commit 40db85d
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 12 deletions.
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

0 comments on commit 40db85d

Please sign in to comment.