MQL5Book/Include/ws/wsinterfaces.mqh
super.admin 1c8e83ce31 convert
2025-05-30 16:09:41 +02:00

190 lines
6.9 KiB
MQL5

//+------------------------------------------------------------------+
//| wsinterfaces.mqh |
//| Copyright 2020-2022, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Defines |
//+------------------------------------------------------------------+
#define WS_APP_TYPE_CLIENT 1
#define WS_APP_TYPE_SERVER 0 // not supported in MQL5, can be used for unmasking only (frame debugging)
#ifndef WS_APP_TYPE
#define WS_APP_TYPE WS_APP_TYPE_CLIENT // masking is enabled in client, disabled in server
#endif
#define WS_BUFFSIZE 1024
#define CRLFCRLF "\r\n\r\n"
//+------------------------------------------------------------------+
//| Communication level abstraction: a wrapper for built-in |
//| Socket-functions or other DLL-based implemenations |
//+------------------------------------------------------------------+
interface IWebSocketTransport
{
int write(const uchar &data[]);
int read(uchar &buffer[]);
bool isConnected(void) const;
bool isReadable(void) const;
bool isWritable(void) const;
int getHandle(void) const;
void close(void);
};
//+------------------------------------------------------------------+
//| Enum with all frame codes defined in WebSocket protocol |
//+------------------------------------------------------------------+
enum WS_FRAME_OPCODE
{
WS_DEFAULT = 0,
WS_CONTINUATION_FRAME = 0x00,
WS_TEXT_FRAME = 0x01,
WS_BINARY_FRAME = 0x02,
WS_CLOSE_FRAME = 0x08,
WS_PING_FRAME = 0x09,
WS_PONG_FRAME = 0x0A
};
//+------------------------------------------------------------------+
//| Interface for WebSocket frames, which compose a message |
//| (defined as a class because of default/nested implementation) |
//+------------------------------------------------------------------+
class IWebSocketFrame
{
public:
//+------------------------------------------------------------------+
//| Interface for static methods in IWebSocketFrame |
//+------------------------------------------------------------------+
class StaticCreator
{
public:
virtual IWebSocketFrame *decode(uchar &data[], IWebSocketFrame *head = NULL) = 0;
virtual IWebSocketFrame *create(WS_FRAME_OPCODE type, const string data = NULL, const bool deflate = false) = 0;
virtual IWebSocketFrame *create(WS_FRAME_OPCODE type, const uchar &data[], const bool deflate = false) = 0;
};
protected:
//+------------------------------------------------------------------+
//| Require all the static methods to exist in P |
//+------------------------------------------------------------------+
template<typename P>
class Creator: public StaticCreator
{
public:
// decode received binary data into a IWebSocketFrame (use head for continuation frames)
virtual IWebSocketFrame *decode(uchar &data[], IWebSocketFrame *head = NULL) override
{
return P::decode(data, head);
}
// create a text/close/other frame with optional payload
virtual IWebSocketFrame *create(WS_FRAME_OPCODE type, const string data = NULL, const bool deflate = false) override
{
return P::create(type, data, deflate);
};
// create a binary/text/close/other frame with payload
virtual IWebSocketFrame *create(WS_FRAME_OPCODE type, const uchar &data[], const bool deflate = false) override
{
return P::create(type, data, deflate);
};
};
public:
// require creator itself to exist, hence all static methods must be implemented
virtual IWebSocketFrame::StaticCreator *getCreator() = 0;
// using frame content, prepare and return its raw data to be sent over network
virtual int encode(uchar &encoded[]) = 0;
// read payload as text
virtual string getData() = 0;
// read payload as raw data, return size
virtual int getData(uchar &buf[]) = 0;
// return frame type (opcode)
virtual WS_FRAME_OPCODE getType() = 0;
// check if the frame is a control frame:
// control frames should be handled internally by websocket classes
virtual bool isControlFrame()
{
return (getType() >= WS_CLOSE_FRAME);
}
virtual bool isReady() { return true; }
virtual bool isFinal() { return true; }
virtual bool isMasked() { return false; }
virtual bool isCompressed() { return false; }
};
//+------------------------------------------------------------------+
//| Interface for WebSocket messages |
//+------------------------------------------------------------------+
class IWebSocketMessage
{
public:
// retreive an array of frames of which this message is composed
virtual void getFrames(IWebSocketFrame *&frames[]) = 0;
// set text as message content
virtual bool setString(const string &data) = 0;
// return message content as text
virtual string getString() = 0;
// set binary data as message content
virtual bool setData(const uchar &data[]) = 0;
// return message content raw
virtual bool getData(uchar &data[]) = 0;
// return if all frames of the message are received
virtual bool isFinalised() = 0;
// add a frame into message
virtual bool takeFrame(IWebSocketFrame *frame) = 0;
};
//+------------------------------------------------------------------+
//| Interface for WebSocket connection functionality |
//+------------------------------------------------------------------+
interface IWebSocketConnection
{
// open a connection
bool handshake(const string url, const string host, const string origin, const string custom = NULL);
// low-level get incoming frame(s) from a server
int readFrame(IWebSocketFrame *&frames[]);
int checkMessages();
// low-level send raw frame (for example, close or ping)
bool sendFrame(IWebSocketFrame *frame);
// low-level send raw message
bool sendMessage(IWebSocketMessage *msg);
// user-level send text
bool sendString(const string msg);
// user-level send binary data
bool sendData(const uchar &data[]);
// close connection
bool disconnect(void);
};
//+------------------------------------------------------------------+
//| Interface for WebSocket events callbacks |
//+------------------------------------------------------------------+
interface IWebSocketObserver
{
void onDisconnect();
void onConnected();
void onMessage(IWebSocketMessage *msg);
};
//+------------------------------------------------------------------+