From 13abf7f0167a3816bf5f571dee06d8bbd93c3723 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 14 Dec 2019 11:59:18 +1300 Subject: [PATCH] WebSocket and WebSocketServer JSDoc --- .../script-engine/src/WebSocketClass.cpp | 30 +++++ libraries/script-engine/src/WebSocketClass.h | 113 ++++++++++++++++++ .../script-engine/src/WebSocketServerClass.h | 66 ++++++++++ 3 files changed, 209 insertions(+) diff --git a/libraries/script-engine/src/WebSocketClass.cpp b/libraries/script-engine/src/WebSocketClass.cpp index 56753f07d1..c02efd8a30 100644 --- a/libraries/script-engine/src/WebSocketClass.cpp +++ b/libraries/script-engine/src/WebSocketClass.cpp @@ -68,6 +68,18 @@ void WebSocketClass::close(QWebSocketProtocol::CloseCode closeCode, QString reas _webSocket->close(closeCode, reason); } +/**jsdoc + * Called when the connection closes. + * @callback WebSocket~onCloseCallback + * @param {WebSocket.CloseData} data - Information on the connection closure. + */ +/**jsdoc + * Information on a connection being closed. + * @typedef {object} WebSocket.CloseData + * @property {WebSocket.CloseCode} code - The reason why the connection was closed. + * @property {string} reason - Description of the reason why the connection was closed. + * @property {boolean} wasClean - true if the connection closed cleanly, false if it didn't. + */ void WebSocketClass::handleOnClose() { bool hasError = (_webSocket->error() != QAbstractSocket::UnknownSocketError); if (_onCloseEvent.isFunction()) { @@ -81,12 +93,26 @@ void WebSocketClass::handleOnClose() { } } +/**jsdoc + * Called when an error occurs. + * @callback WebSocket~onErrorCallback + */ void WebSocketClass::handleOnError(QAbstractSocket::SocketError error) { if (_onErrorEvent.isFunction()) { _onErrorEvent.call(); } } +/**jsdoc + * Triggered when a message is received. + * @callback WebSocket~onMessageCallback + * @param {WebSocket.MessageData} message - The message received. + */ +/**jsdoc + * A message received on a WebSocket connection. + * @typedef {object} WebSocket.MessageData + * @property {string} data - The message content. + */ void WebSocketClass::handleOnMessage(const QString& message) { if (_onMessageEvent.isFunction()) { QScriptValueList args; @@ -97,6 +123,10 @@ void WebSocketClass::handleOnMessage(const QString& message) { } } +/**jsdoc + * Called when the connection opens. + * @callback WebSocket~onOpenCallback + */ void WebSocketClass::handleOnOpen() { if (_onOpenEvent.isFunction()) { _onOpenEvent.call(); diff --git a/libraries/script-engine/src/WebSocketClass.h b/libraries/script-engine/src/WebSocketClass.h index dbc9729c61..56fb334152 100644 --- a/libraries/script-engine/src/WebSocketClass.h +++ b/libraries/script-engine/src/WebSocketClass.h @@ -16,6 +16,68 @@ #include #include +/**jsdoc + * Provides a bi-direcctional, event-driven communication session between the script and another WebSocket connection. It is a + * near-complete implementation of the WebSocket API described in the Mozilla docs: + * https://developer.mozilla.org/en-US/docs/Web/API/WebSocket.

+ * + *

Constructed by new WebSocket(...) in Interface, client entity, avatar, and server entity scripts, or the + * {@link WebSocketServer} class in server entity and assignment client scripts. + * + *

Note: Does not support secure, wss: protocol.

+ * + * @class WebSocket + * @param {string|WebSocket} urlOrWebSocket - The URL to connect to or an existing {@link WebSocket} to reuse the connection of. + * + * @hifi-interface + * @hifi-client-entity + * @hifi-avatar + * @hifi-server-entity + * @hifi-assignment-client + * + * @property {string} binaryType="blob" - Not used. + * @property {number} bufferedAmount=0 - Not implemented. Read-only. + * @property {string} extensions="" - Not implemented. Read-only. + * + * @property {WebSocket~onOpenCallback} onopen - Function called when the connection opens. + * @property {WebSocket~onMessageCallback} onmessage - Function called when a message is received. + * @property {WebSocket~onErrorCallback} onerror - Function called when an error occurs. + * @property {WebSocket~onCloseCallback} onclose - Function called when the connection closes. + * + * @property {string} protocol="" - Not implemented. Read-only. + * @property {WebSocket.ReadyState} readyState - The state of the connection. Read-only. + * @property {string} url - The URL to connect to. Read-only. + * + * @property {WebSocket.ReadyState} CONNECTING - The connection is opening. Read-only. + * @property {WebSocket.ReadyState} OPEN - The connection is open. Read-only. + * @property {WebSocket.ReadyState} CLOSING - The connection is closing. Read-only. + * @property {WebSocket.ReadyState} CLOSED - The connection is closed. Read-only. + * + * @example Echo a message off websocket.org. + * print("Create WebSocket"); + * var WEBSOCKET_PING_URL = "ws://echo.websocket.org"; + * var webSocket = new WebSocket(WEBSOCKET_PING_URL); + * + * webSocket.onclose = function (data) { + * print("WebSocket closed"); + * print("Ready state =", webSocket.readyState); // 3 + * }; + * + * webSocket.onmessage = function (data) { + * print("Message received:", data.data); + * + * print("Close WebSocket"); + * webSocket.close(); + * }; + * + * webSocket.onopen = function () { + * print("WebSocket opened"); + * print("Ready state =", webSocket.readyState); // 1 + * + * print("Send a test message"); + * webSocket.send("Test message"); + * }; + */ class WebSocketClass : public QObject { Q_OBJECT Q_PROPERTY(QString binaryType READ getBinaryType WRITE setBinaryType) @@ -43,6 +105,21 @@ public: static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + /**jsdoc + * The state of a WebSocket connection. + * + * + * + * + * + * + * + * + * + * + *
ValueNameDescription
0CONNECTINGThe connection is opening.
1OPENThe connection is open.
2CLOSINGThe connection is closing.
3CLOSEDThe connection is closed.
+ * @typedef {number} WebSocket.ReadyState + */ enum ReadyState { CONNECTING = 0, OPEN, @@ -100,8 +177,44 @@ public: QScriptValue getOnOpen() { return _onOpenEvent; } public slots: + + /**jsdoc + * Sends a message on the connection. + * @function WebSocket.send + * @param {string|object} message - The message to send. If an object, it is converted to a string. + */ void send(QScriptValue message); + /**jsdoc + * Closes the connection. + * @function WebSocket.close + * @param {WebSocket.CloseCode} [closeCode=1000] - The reason for closing. + * @param {string} [reason=""] - A description of the reason for closing. + */ + /**jsdoc + * The reason why the connection was closed. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
ValueNameDescription
1000NormalNormal closure.
1001GoingAwayGoing away.
1002ProtocolErrorProtocol error.
1003DatatypeNotSupportedUnsupported data.
1004Reserved1004Reserved.
1005MissingStatusCodeNo status received.
1006AbnormalDisconnectionabnormal closure.
1007WrongDatatypeInvalid frame payload data.
1008PolicyViolatedPolicy violation.
1009TooMuchDataMessage too big.
1010MissingExtensionMandatory extension missing.
1011BadOperationInternal server error.
1015TlsHandshakeFailedTLS handshake failed.
+ * @typedef {number} WebSocket.CloseCode + */ void close(); void close(QWebSocketProtocol::CloseCode closeCode); void close(QWebSocketProtocol::CloseCode closeCode, QString reason); diff --git a/libraries/script-engine/src/WebSocketServerClass.h b/libraries/script-engine/src/WebSocketServerClass.h index 972bf9c032..dfd277fec1 100644 --- a/libraries/script-engine/src/WebSocketServerClass.h +++ b/libraries/script-engine/src/WebSocketServerClass.h @@ -17,6 +17,60 @@ #include #include "WebSocketClass.h" +/**jsdoc + * Manages {@link WebSocket}s in server entity and assignment client scripts. + * + * @class WebSocketServer + * + * @hifi-server-entity + * @hifi-assignment-client + * + * @property {string} url - The URL that the server is listening on. Read-only. + * @property {number} port - The port that the server is listening on. Read-only. + * @property {boolean} listening - true if the server is listening for incoming connections, false if + * it isn't. Read-only. + * + * @example + * // Server entity script. Echoes received message back to sender. + * (function () { + * print("Create WebSocketServer"); + * var webSocketServer = new WebSocketServer(); + * print("Server url:", webSocketServer.url); + * + * function onNewConnection(webSocket) { + * print("New connection"); + * + * webSocket.onmessage = function (message) { + * print("Message received:", message.data); + * + * var returnMessage = message.data + " back!"; + * print("Echo a message back:", returnMessage); + * webSocket.send(message.data + " back!"); + * }; + * } + * + * webSocketServer.newConnection.connect(onNewConnection); + * }) + * + * @example + * // Interface script. Bounces message off server entity script. + * // Use the server URL reported by the server entity script. + * var WEBSOCKET_PING_URL = "ws://127.0.0.1:nnnnn"; + * var TEST_MESSAGE = "Hello"; + * + * print("Create WebSocket"); + * var webSocket = new WebSocket(WEBSOCKET_PING_URL); + * + * webSocket.onmessage = function(data) { + * print("Message received:", data.data); + * }; + * + * webSocket.onopen = function() { + * print("WebSocket opened"); + * print("Send test message:", TEST_MESSAGE); + * webSocket.send(TEST_MESSAGE); + * }; + */ class WebSocketServerClass : public QObject { Q_OBJECT Q_PROPERTY(QString url READ getURL) @@ -34,6 +88,11 @@ public: static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); public slots: + + /**jsdoc + * Closes all connections and closes the WebSocketServer. + * @function WebSocketServer.close + */ void close(); private: @@ -45,6 +104,13 @@ private slots: void onNewConnection(); signals: + + /**jsdoc + * Triggered when there is a new connection. + * @function WebSocketServer.newConnection + * @param {WebSocket} webSocket - The {@link WebSocket} for the new connection. + * @returns {Signal} + */ void newConnection(WebSocketClass* client); };
Echo a message back to sender.