forked from rosh/MQL5Book
190 lines
6.9 KiB
MQL5
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);
| |||
};
| |||
//+------------------------------------------------------------------+
|