2016-04-23 15:11:32 +03:00
/*
Asynchronous WebServer library for Espressif MCUs
Copyright ( c ) 2016 Hristo Gochkov . All rights reserved .
This file is part of the esp8266 core for Arduino environment .
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 2.1 of the License , or ( at your option ) any later version .
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# ifndef ASYNCWEBSOCKET_H_
# define ASYNCWEBSOCKET_H_
# include <Arduino.h>
2017-09-07 22:01:58 +03:00
# ifdef ESP32
2024-06-27 20:34:10 +02:00
# include <AsyncTCP.h>
# include <mutex>
# ifndef WS_MAX_QUEUED_MESSAGES
# define WS_MAX_QUEUED_MESSAGES 32
# endif
2024-06-14 01:34:29 +05:30
# elif defined(ESP8266)
2024-06-27 20:34:10 +02:00
# include <ESPAsyncTCP.h>
# ifndef WS_MAX_QUEUED_MESSAGES
# define WS_MAX_QUEUED_MESSAGES 8
# endif
2024-06-14 01:34:29 +05:30
# elif defined(TARGET_RP2040)
# include <AsyncTCP_RP2040W.h>
# ifndef WS_MAX_QUEUED_MESSAGES
# define WS_MAX_QUEUED_MESSAGES 32
# endif
2024-01-12 19:02:29 +01:00
# endif
2024-06-14 01:34:29 +05:30
2016-04-23 15:11:32 +03:00
# include <ESPAsyncWebServer.h>
2020-12-30 19:25:25 -05:00
# include <memory>
2020-12-29 12:56:39 -05:00
2019-06-23 06:58:25 +02:00
# ifdef ESP8266
2024-06-27 20:34:10 +02:00
# include <Hash.h>
# ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library
# include <../src/Hash.h>
# endif
2019-06-23 06:58:25 +02:00
# endif
2024-06-10 11:46:42 +02:00
# ifndef DEFAULT_MAX_WS_CLIENTS
2024-06-27 20:34:10 +02:00
# ifdef ESP32
# define DEFAULT_MAX_WS_CLIENTS 8
# else
# define DEFAULT_MAX_WS_CLIENTS 4
# endif
2024-06-10 11:46:42 +02:00
# endif
2019-09-24 20:42:40 +01:00
2024-06-09 16:06:13 +09:00
using AsyncWebSocketSharedBuffer = std : : shared_ptr < std : : vector < uint8_t > > ;
2016-04-23 15:11:32 +03:00
class AsyncWebSocket ;
class AsyncWebSocketResponse ;
class AsyncWebSocketClient ;
class AsyncWebSocketControl ;
typedef struct {
2017-11-06 14:58:07 +01:00
/** Message type as defined by enum AwsFrameType.
* Note : Applications will only see WS_TEXT and WS_BINARY .
* All other types are handled by the library . */
2016-04-23 15:11:32 +03:00
uint8_t message_opcode ;
2017-11-06 14:58:07 +01:00
/** Frame number of a fragmented message. */
2016-04-23 15:11:32 +03:00
uint32_t num ;
2017-11-06 14:58:07 +01:00
/** Is this the last frame in a fragmented message ?*/
2016-04-23 15:11:32 +03:00
uint8_t final ;
2017-11-06 14:58:07 +01:00
/** Is this frame masked? */
2016-04-23 15:11:32 +03:00
uint8_t masked ;
2017-11-06 14:58:07 +01:00
/** Message type as defined by enum AwsFrameType.
* This value is the same as message_opcode for non - fragmented
* messages , but may also be WS_CONTINUATION in a fragmented message . */
2016-04-23 15:11:32 +03:00
uint8_t opcode ;
2017-11-06 14:58:07 +01:00
/** Length of the current frame.
* This equals the total length of the message if num = = 0 & & final = = true */
2016-04-23 15:11:32 +03:00
uint64_t len ;
2017-11-06 14:58:07 +01:00
/** Mask key */
2016-04-23 15:11:32 +03:00
uint8_t mask [ 4 ] ;
2017-11-06 14:58:07 +01:00
/** Offset of the data inside the current frame. */
2016-04-23 15:11:32 +03:00
uint64_t index ;
} AwsFrameInfo ;
2024-06-27 20:34:10 +02:00
typedef enum { WS_DISCONNECTED ,
WS_CONNECTED ,
WS_DISCONNECTING } AwsClientStatus ;
typedef enum { WS_CONTINUATION ,
WS_TEXT ,
WS_BINARY ,
WS_DISCONNECT = 0x08 ,
WS_PING ,
WS_PONG } AwsFrameType ;
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 ;
2016-04-23 15:11:32 +03:00
2024-01-25 23:42:12 +01:00
class AsyncWebSocketMessageBuffer {
2024-06-27 20:34:10 +02:00
friend AsyncWebSocket ;
friend AsyncWebSocketClient ;
2024-01-25 23:42:12 +01:00
private :
2024-06-09 16:06:13 +09:00
AsyncWebSocketSharedBuffer _buffer ;
2024-01-25 23:42:12 +01:00
public :
2024-06-27 20:34:10 +02:00
AsyncWebSocketMessageBuffer ( ) { }
2024-06-09 16:06:13 +09:00
explicit AsyncWebSocketMessageBuffer ( size_t size ) ;
AsyncWebSocketMessageBuffer ( const uint8_t * data , size_t size ) ;
//~AsyncWebSocketMessageBuffer();
2024-01-25 23:42:12 +01:00
bool reserve ( size_t size ) ;
uint8_t * get ( ) { return _buffer - > data ( ) ; }
size_t length ( ) const { return _buffer - > size ( ) ; }
} ;
2024-06-27 20:34:10 +02:00
class AsyncWebSocketMessage {
private :
2024-06-09 16:06:13 +09:00
AsyncWebSocketSharedBuffer _WSbuffer ;
2021-01-02 20:07:28 -05:00
uint8_t _opcode { WS_TEXT } ;
bool _mask { false } ;
AwsMessageStatus _status { WS_MSG_ERROR } ;
size_t _sent { } ;
size_t _ack { } ;
size_t _acked { } ;
2020-12-30 18:05:02 -05:00
2024-06-27 20:34:10 +02:00
public :
AsyncWebSocketMessage ( AsyncWebSocketSharedBuffer buffer , uint8_t opcode = WS_TEXT , bool mask = false ) ;
2020-12-30 18:05:02 -05:00
2021-01-02 20:07:28 -05:00
bool finished ( ) const { return _status ! = WS_MSG_SENDING ; }
bool betweenFrames ( ) const { return _acked = = _ack ; }
2020-12-30 18:05:02 -05:00
2021-01-02 20:07:28 -05:00
void ack ( size_t len , uint32_t time ) ;
2024-06-27 20:34:10 +02:00
size_t send ( AsyncClient * client ) ;
2020-12-30 18:05:02 -05:00
} ;
2016-04-23 15:11:32 +03:00
class AsyncWebSocketClient {
private :
2024-06-27 20:34:10 +02:00
AsyncClient * _client ;
AsyncWebSocket * _server ;
2016-04-23 15:11:32 +03:00
uint32_t _clientId ;
AwsClientStatus _status ;
2024-06-26 16:50:45 +09:00
# ifdef ESP32
mutable std : : mutex _lock ;
# endif
2020-12-29 18:49:23 -05:00
std : : deque < AsyncWebSocketControl > _controlQueue ;
2021-01-02 20:07:28 -05:00
std : : deque < AsyncWebSocketMessage > _messageQueue ;
2024-06-01 21:44:20 +02:00
bool closeWhenFull = true ;
2016-04-23 15:11:32 +03:00
uint8_t _pstate ;
AwsFrameInfo _pinfo ;
2016-05-28 03:50:38 +03:00
uint32_t _lastMessageTime ;
uint32_t _keepAlivePeriod ;
2024-06-27 20:34:10 +02:00
void _queueControl ( uint8_t opcode , const uint8_t * data = NULL , size_t len = 0 , bool mask = false ) ;
void _queueMessage ( AsyncWebSocketSharedBuffer buffer , uint8_t opcode = WS_TEXT , bool mask = false ) ;
2016-04-23 15:11:32 +03:00
void _runQueue ( ) ;
2020-09-12 14:40:39 +03:00
void _clearQueue ( ) ;
2016-04-23 15:11:32 +03:00
public :
2024-06-27 20:34:10 +02:00
void * _tempObject ;
2017-10-01 10:13:11 +08:00
2024-06-27 20:34:10 +02:00
AsyncWebSocketClient ( AsyncWebServerRequest * request , AsyncWebSocket * server ) ;
2016-04-23 15:11:32 +03:00
~ AsyncWebSocketClient ( ) ;
2024-06-27 20:34:10 +02:00
// client id increments for the given server
2020-12-29 17:43:35 -05:00
uint32_t id ( ) const { return _clientId ; }
AwsClientStatus status ( ) const { return _status ; }
AsyncClient * client ( ) { return _client ; }
const AsyncClient * client ( ) const { return _client ; }
2024-06-27 20:34:10 +02:00
AsyncWebSocket * server ( ) { return _server ; }
const AsyncWebSocket * server ( ) const { return _server ; }
AwsFrameInfo const & pinfo ( ) const { return _pinfo ; }
2016-05-03 04:49:51 +03:00
2024-06-01 21:44:20 +02:00
// - If "true" (default), the connection will be closed if the message queue is full.
// This is the default behavior in yubox-node-org, which is not silently discarding messages but instead closes the connection.
2024-06-27 20:34:10 +02:00
// The big issue with this behavior is that is can cause the UI to automatically re-create a new WS connection, which can be filled again,
2024-06-01 21:44:20 +02:00
// and so on, causing a resource exhaustion.
2024-06-27 20:34:10 +02:00
//
2024-06-01 21:44:20 +02:00
// - If "false", the incoming message will be discarded if the queue is full.
// This is the default behavior in the original ESPAsyncWebServer library from me-no-dev.
// This behavior allows the best performance at the expense of unreliable message delivery in case the queue is full (some messages may be lost).
2024-06-27 20:34:10 +02:00
//
2024-06-01 21:44:20 +02:00
// - In any case, when the queue is full, a message is logged.
// - IT is recommended to use the methods queueIsFull(), availableForWriteAll(), availableForWrite(clientId) to check if the queue is full before sending a message.
2024-06-27 20:34:10 +02:00
//
2024-06-01 21:44:20 +02:00
// Usage:
// - can be set in the onEvent listener when connecting (event type is: WS_EVT_CONNECT)
2024-06-27 20:34:10 +02:00
//
// Use cases:,
2024-06-01 21:44:20 +02:00
// - if using websocket to send logging messages, maybe some loss is acceptable.
// - But if using websocket to send UI update messages, maybe the connection should be closed and the UI redrawn.
void setCloseClientOnQueueFull ( bool close ) { closeWhenFull = close ; }
bool willCloseClientOnQueueFull ( ) const { return closeWhenFull ; }
2020-12-29 17:43:35 -05:00
IPAddress remoteIP ( ) const ;
2024-06-27 20:34:10 +02:00
uint16_t remotePort ( ) const ;
2016-04-23 15:11:32 +03:00
2021-01-02 20:52:41 -05:00
bool shouldBeDeleted ( ) const { return ! _client ; }
2024-06-27 20:34:10 +02:00
// control frames
void close ( uint16_t code = 0 , const char * message = NULL ) ;
void ping ( const uint8_t * data = NULL , size_t len = 0 ) ;
2016-04-23 15:11:32 +03:00
2024-06-27 20:34:10 +02:00
// set auto-ping period in seconds. disabled if zero (default)
void keepAlivePeriod ( uint16_t seconds ) {
2016-05-28 03:50:38 +03:00
_keepAlivePeriod = seconds * 1000 ;
}
2024-06-27 20:34:10 +02:00
uint16_t keepAlivePeriod ( ) {
2016-05-28 03:50:38 +03:00
return ( uint16_t ) ( _keepAlivePeriod / 1000 ) ;
}
2024-06-27 20:34:10 +02:00
// data packets
void message ( AsyncWebSocketSharedBuffer buffer , uint8_t opcode = WS_TEXT , bool mask = false ) { _queueMessage ( buffer , opcode , mask ) ; }
2020-12-29 17:43:35 -05:00
bool queueIsFull ( ) const ;
2020-12-29 18:49:23 -05:00
size_t queueLen ( ) const ;
2016-04-23 15:11:32 +03:00
2024-06-27 20:34:10 +02:00
size_t printf ( const char * format , . . . ) __attribute__ ( ( format ( printf , 2 , 3 ) ) ) ;
2021-01-02 20:07:28 -05:00
2024-06-09 16:06:13 +09:00
void text ( AsyncWebSocketSharedBuffer buffer ) ;
2024-06-27 20:34:10 +02:00
void text ( const uint8_t * message , size_t len ) ;
void text ( const char * message , size_t len ) ;
void text ( const char * message ) ;
void text ( const String & message ) ;
void text ( AsyncWebSocketMessageBuffer * buffer ) ;
2016-04-23 15:11:32 +03:00
2024-06-09 16:06:13 +09:00
void binary ( AsyncWebSocketSharedBuffer buffer ) ;
2024-06-27 20:34:10 +02:00
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 ( AsyncWebSocketMessageBuffer * buffer ) ;
2016-04-23 15:11:32 +03:00
2020-12-30 18:05:02 -05:00
bool canSend ( ) const ;
2019-06-22 19:47:43 +03:00
2024-06-27 20:34:10 +02:00
// system callbacks (do not call)
2016-04-23 15:11:32 +03:00
void _onAck ( size_t len , uint32_t time ) ;
void _onError ( int8_t ) ;
void _onPoll ( ) ;
void _onTimeout ( uint32_t time ) ;
void _onDisconnect ( ) ;
2024-06-27 20:34:10 +02:00
void _onData ( void * pbuf , size_t plen ) ;
2024-08-08 12:23:46 +02:00
# ifdef ESP8266
size_t printf_P ( PGM_P formatP , . . . ) __attribute__ ( ( format ( printf , 2 , 3 ) ) ) ;
void text ( const __FlashStringHelper * message ) ;
void binary ( const __FlashStringHelper * message , size_t len ) ;
# endif
2016-04-23 15:11:32 +03:00
} ;
2024-06-27 20:34:10 +02:00
using AwsHandshakeHandler = std : : function < bool ( AsyncWebServerRequest * request ) > ;
using AwsEventHandler = std : : function < void ( AsyncWebSocket * server , AsyncWebSocketClient * client , AwsEventType type , void * arg , uint8_t * data , size_t len ) > ;
2016-04-23 15:11:32 +03:00
2024-06-27 20:34:10 +02:00
// WebServer Handler implementation that plays the role of a socket server
class AsyncWebSocket : public AsyncWebHandler {
2016-04-23 15:11:32 +03:00
private :
String _url ;
2020-12-29 18:10:26 -05:00
std : : list < AsyncWebSocketClient > _clients ;
2016-04-23 15:11:32 +03:00
uint32_t _cNextId ;
2024-06-09 16:06:13 +09:00
AwsEventHandler _eventHandler { nullptr } ;
2024-06-27 20:34:10 +02:00
AwsHandshakeHandler _handshakeHandler ;
2016-05-25 19:48:04 +03:00
bool _enabled ;
2024-06-26 16:50:45 +09:00
# ifdef ESP32
mutable std : : mutex _lock ;
# endif
2019-09-12 17:56:13 +01:00
2016-04-23 15:11:32 +03:00
public :
2024-06-27 20:34:10 +02:00
explicit AsyncWebSocket ( const char * url ) : _url ( url ) , _cNextId ( 1 ) , _enabled ( true ) { }
AsyncWebSocket ( const String & url ) : _url ( url ) , _cNextId ( 1 ) , _enabled ( true ) { }
2024-09-29 21:29:59 +02:00
~ AsyncWebSocket ( ) { } ;
2024-06-27 20:34:10 +02:00
const char * url ( ) const { return _url . c_str ( ) ; }
void enable ( bool e ) { _enabled = e ; }
2016-11-27 17:42:09 +02:00
bool enabled ( ) const { return _enabled ; }
2019-06-22 18:51:01 +02:00
bool availableForWriteAll ( ) ;
bool availableForWrite ( uint32_t id ) ;
2016-04-23 15:11:32 +03:00
2016-11-27 17:42:09 +02:00
size_t count ( ) const ;
2024-06-27 20:34:10 +02:00
AsyncWebSocketClient * client ( uint32_t id ) ;
bool hasClient ( uint32_t id ) { return client ( id ) ! = nullptr ; }
2016-04-23 15:11:32 +03:00
2024-06-27 20:34:10 +02:00
void close ( uint32_t id , uint16_t code = 0 , const char * message = NULL ) ;
void closeAll ( uint16_t code = 0 , const char * message = NULL ) ;
2019-09-24 20:42:40 +01:00
void cleanupClients ( uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS ) ;
2016-04-23 15:11:32 +03:00
2024-06-27 20:34:10 +02:00
void ping ( uint32_t id , const uint8_t * data = NULL , size_t len = 0 ) ;
void pingAll ( const uint8_t * data = NULL , size_t len = 0 ) ; // done
2016-04-23 15:11:32 +03:00
2024-06-27 20:34:10 +02:00
void text ( uint32_t id , const uint8_t * message , size_t len ) ;
void text ( uint32_t id , const char * message , size_t len ) ;
void text ( uint32_t id , const char * message ) ;
void text ( uint32_t id , const String & message ) ;
void text ( uint32_t id , AsyncWebSocketMessageBuffer * buffer ) ;
2024-06-09 16:06:13 +09:00
void text ( uint32_t id , AsyncWebSocketSharedBuffer buffer ) ;
2016-04-23 15:11:32 +03:00
2024-06-27 20:34:10 +02:00
void textAll ( const uint8_t * message , size_t len ) ;
void textAll ( const char * message , size_t len ) ;
void textAll ( const char * message ) ;
void textAll ( const String & message ) ;
void textAll ( AsyncWebSocketMessageBuffer * buffer ) ;
2024-06-09 16:06:13 +09:00
void textAll ( AsyncWebSocketSharedBuffer buffer ) ;
2016-04-23 15:11:32 +03:00
2024-06-27 20:34:10 +02:00
void binary ( uint32_t id , const uint8_t * message , size_t len ) ;
void binary ( uint32_t id , const char * message , size_t len ) ;
void binary ( uint32_t id , const char * message ) ;
void binary ( uint32_t id , const String & message ) ;
void binary ( uint32_t id , AsyncWebSocketMessageBuffer * buffer ) ;
2024-06-09 16:06:13 +09:00
void binary ( uint32_t id , AsyncWebSocketSharedBuffer buffer ) ;
2016-04-23 15:11:32 +03:00
2024-06-27 20:34:10 +02:00
void binaryAll ( const uint8_t * message , size_t len ) ;
void binaryAll ( const char * message , size_t len ) ;
void binaryAll ( const char * message ) ;
void binaryAll ( const String & message ) ;
void binaryAll ( AsyncWebSocketMessageBuffer * buffer ) ;
2024-06-09 16:06:13 +09:00
void binaryAll ( AsyncWebSocketSharedBuffer buffer ) ;
2016-04-23 15:11:32 +03:00
2024-06-27 20:34:10 +02:00
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 ) ) ) ;
2024-06-28 00:45:05 +09:00
2024-07-02 21:49:18 +09:00
# ifdef ESP8266
2024-08-08 12:23:46 +02:00
void text ( uint32_t id , const __FlashStringHelper * message ) ;
void textAll ( const __FlashStringHelper * message ) ;
void binary ( uint32_t id , const __FlashStringHelper * message , size_t len ) ;
void binaryAll ( const __FlashStringHelper * message , size_t len ) ;
2024-06-27 20:34:10 +02:00
size_t printf_P ( uint32_t id , PGM_P formatP , . . . ) __attribute__ ( ( format ( printf , 3 , 4 ) ) ) ;
size_t printfAll_P ( PGM_P formatP , . . . ) __attribute__ ( ( format ( printf , 2 , 3 ) ) ) ;
2024-06-28 00:45:05 +09:00
# endif
2016-04-23 15:11:32 +03:00
2024-09-29 21:29:59 +02:00
void onEvent ( AwsEventHandler handler ) { _eventHandler = handler ; }
void handleHandshake ( AwsHandshakeHandler handler ) { _handshakeHandler = handler ; }
2017-03-14 13:55:39 +00:00
2024-06-27 20:34:10 +02:00
// system callbacks (do not call)
uint32_t _getNextId ( ) { return _cNextId + + ; }
AsyncWebSocketClient * _newClient ( AsyncWebServerRequest * request ) ;
void _handleEvent ( AsyncWebSocketClient * client , AwsEventType type , void * arg , uint8_t * data , size_t len ) ;
virtual bool canHandle ( AsyncWebServerRequest * request ) override final ;
virtual void handleRequest ( AsyncWebServerRequest * request ) override final ;
2024-01-25 23:42:12 +01:00
2024-06-27 20:34:10 +02:00
// messagebuffer functions/objects.
AsyncWebSocketMessageBuffer * makeBuffer ( size_t size = 0 ) ;
AsyncWebSocketMessageBuffer * makeBuffer ( const uint8_t * data , size_t size ) ;
2024-01-25 23:42:12 +01:00
2024-06-27 20:34:10 +02:00
const std : : list < AsyncWebSocketClient > & getClients ( ) const { return _clients ; }
2016-04-23 15:11:32 +03:00
} ;
2024-06-27 20:34:10 +02:00
// WebServer response to authenticate the socket and detach the tcp client from the web server request
class AsyncWebSocketResponse : public AsyncWebServerResponse {
2016-04-23 15:11:32 +03:00
private :
String _content ;
2024-06-27 20:34:10 +02:00
AsyncWebSocket * _server ;
2016-04-23 15:11:32 +03:00
public :
2024-06-27 20:34:10 +02:00
AsyncWebSocketResponse ( const String & key , AsyncWebSocket * server ) ;
void _respond ( AsyncWebServerRequest * request ) ;
size_t _ack ( AsyncWebServerRequest * request , size_t len , uint32_t time ) ;
2016-11-28 22:00:33 +02:00
bool _sourceValid ( ) const { return true ; }
2016-04-23 15:11:32 +03:00
} ;
# endif /* ASYNCWEBSOCKET_H_ */