UNPKG

react-stomp

Version:

React websocket component with STOMP over SockJS

361 lines (282 loc) 11.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _react = _interopRequireDefault(require("react")); var _sockjsClient = _interopRequireDefault(require("sockjs-client")); var _stompjs = _interopRequireDefault(require("stompjs")); var _propTypes = _interopRequireDefault(require("prop-types")); var _difference = _interopRequireDefault(require("lodash/difference")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /** * React component for SockJS-client with STOMP messaging protocol. * * @version 5.0.0 * @author [lahsivjar] (https://github.com/lahsivjar) * @see {@link https://stomp.github.io/|STOMP} * @see {@link https://github.com/sockjs/sockjs-client|StompJS} */ var SockJsClient = /*#__PURE__*/ function (_React$Component) { _inherits(SockJsClient, _React$Component); function SockJsClient(props) { var _this; _classCallCheck(this, SockJsClient); _this = _possibleConstructorReturn(this, _getPrototypeOf(SockJsClient).call(this, props)); _defineProperty(_assertThisInitialized(_this), "_initStompClient", function () { // Websocket held by stompjs can be opened only once _this.client = _stompjs["default"].over(new _sockjsClient["default"](_this.props.url, null, _this.props.options)); _this.client.heartbeat.outgoing = _this.props.heartbeat; _this.client.heartbeat.incoming = _this.props.heartbeat; if (Object.keys(_this.props).includes('heartbeatIncoming')) { _this.client.heartbeat.incoming = _this.props.heartbeatIncoming; } if (Object.keys(_this.props).includes('heartbeatOutgoing')) { _this.client.heartbeat.outgoing = _this.props.heartbeatOutgoing; } if (!_this.props.debug) { _this.client.debug = function () {}; } }); _defineProperty(_assertThisInitialized(_this), "_cleanUp", function () { _this.setState({ connected: false }); _this.retryCount = 0; _this.subscriptions.clear(); }); _defineProperty(_assertThisInitialized(_this), "_log", function (msg) { if (_this.props.debug) { console.log(msg); } }); _defineProperty(_assertThisInitialized(_this), "_subscribe", function (topic) { if (!_this.subscriptions.has(topic)) { var subscribeHeaders = Object.assign({}, _this.props.subscribeHeaders); var sub = _this.client.subscribe(topic, function (msg) { _this.props.onMessage(_this._processMessage(msg.body), msg.headers.destination); }, subscribeHeaders); _this.subscriptions.set(topic, sub); } }); _defineProperty(_assertThisInitialized(_this), "_processMessage", function (msgBody) { try { return JSON.parse(msgBody); } catch (e) { return msgBody; } }); _defineProperty(_assertThisInitialized(_this), "_unsubscribe", function (topic) { var sub = _this.subscriptions.get(topic); sub.unsubscribe(); _this.subscriptions["delete"](topic); }); _defineProperty(_assertThisInitialized(_this), "_connect", function () { _this._initStompClient(); _this.client.connect(_this.props.headers, function () { _this.setState({ connected: true }); _this.props.topics.forEach(function (topic) { _this._subscribe(topic); }); _this.props.onConnect(); }, function (error) { if (error) { if (Object.keys(_this.props).includes('onConnectFailure')) { _this.props.onConnectFailure(error); } else { _this._log(error.stack); } } if (_this.state.connected) { _this._cleanUp(); // onDisconnect should be called only once per connect _this.props.onDisconnect(); } if (_this.props.autoReconnect && !_this.state.explicitDisconnect) { _this._timeoutId = setTimeout(_this._connect, _this.props.getRetryInterval(_this.retryCount++)); } }); }); _defineProperty(_assertThisInitialized(_this), "connect", function () { _this.setState({ explicitDisconnect: false }); if (!_this.state.connected) { _this._connect(); } }); _defineProperty(_assertThisInitialized(_this), "disconnect", function () { // On calling disconnect explicitly no effort will be made to reconnect // Clear timeoutId in case the component is trying to reconnect if (_this._timeoutId) { clearTimeout(_this._timeoutId); _this._timeoutId = null; } _this.setState({ explicitDisconnect: true }); if (_this.state.connected) { _this.subscriptions.forEach(function (subid, topic) { _this._unsubscribe(topic); }); _this.client.disconnect(function () { _this._cleanUp(); _this.props.onDisconnect(); _this._log('Stomp client is successfully disconnected!'); }); } }); _defineProperty(_assertThisInitialized(_this), "sendMessage", function (topic, msg) { var optHeaders = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; if (_this.state.connected) { _this.client.send(topic, optHeaders, msg); } else { throw new Error('Send error: SockJsClient is disconnected'); } }); _this.state = { connected: false, // False if disconnect method is called without a subsequent connect explicitDisconnect: false }; _this.subscriptions = new Map(); _this.retryCount = 0; return _this; } _createClass(SockJsClient, [{ key: "componentDidMount", value: function componentDidMount() { this._connect(); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this.disconnect(); } }, { key: "shouldComponentUpdate", value: function shouldComponentUpdate(nextProps, nextState) { return false; } /* eslint camelcase: ["error", {allow: ["UNSAFE_componentWillReceiveProps"]}] */ }, { key: "UNSAFE_componentWillReceiveProps", value: function UNSAFE_componentWillReceiveProps(nextProps) { var _this2 = this; if (this.state.connected) { // Subscribe to new topics (0, _difference["default"])(nextProps.topics, this.props.topics).forEach(function (newTopic) { _this2._log('Subscribing to topic: ' + newTopic); _this2._subscribe(newTopic); }); // Unsubscribe from old topics (0, _difference["default"])(this.props.topics, nextProps.topics).forEach(function (oldTopic) { _this2._log('Unsubscribing from topic: ' + oldTopic); _this2._unsubscribe(oldTopic); }); } } }, { key: "render", value: function render() { return null; } }]); return SockJsClient; }(_react["default"].Component); _defineProperty(SockJsClient, "defaultProps", { onConnect: function onConnect() {}, onDisconnect: function onDisconnect() {}, getRetryInterval: function getRetryInterval(count) { return 1000 * count; }, options: {}, headers: {}, subscribeHeaders: {}, autoReconnect: true, debug: false, heartbeat: 10000 }); _defineProperty(SockJsClient, "propTypes", { /** * HTTP URL of the endpoint to connect. */ url: _propTypes["default"].string.isRequired, /** * Additional options to pass to the underlying SockJS constructor. * * @see [SockJS-options](https://github.com/sockjs/sockjs-client#sockjs-client-api) */ options: _propTypes["default"].object, /** * Array of topics to subscribe to. */ topics: _propTypes["default"].array.isRequired, /** * Callback after connection is established. */ onConnect: _propTypes["default"].func, /** * Callback after connection is lost. */ onDisconnect: _propTypes["default"].func, /** * Gets called to find the time interval for next retry. Defaults to a function returing retryCount seconds. * * @param {number} retryCount number of retries for the current disconnect */ getRetryInterval: _propTypes["default"].func, /** * Callback when a message is recieved. * * @param {(string|Object)} msg message received from server, if JSON format then object * @param {string} topic the topic on which the message was received */ onMessage: _propTypes["default"].func.isRequired, /** * Headers that will be passed to the server or broker with STOMP's connection frame. */ headers: _propTypes["default"].object, /** * Headers that will be passed when subscribing to a destination. */ subscribeHeaders: _propTypes["default"].object, /** * Should the client try to automatically connect in an event of disconnection. */ autoReconnect: _propTypes["default"].bool, /** * Enable debugging mode. */ debug: _propTypes["default"].bool, /** * Number of milliseconds to send and expect heartbeat messages. */ heartbeat: _propTypes["default"].number, /** * Number of milliseconds to expect heartbeat messages */ heartbeatIncoming: _propTypes["default"].number, /** * Number of milliseconds to send heartbeat messages */ heartbeatOutgoing: _propTypes["default"].number, /** * Callback if connection could not be established */ onConnectFailure: _propTypes["default"].func }); var _default = SockJsClient; exports["default"] = _default;