UNPKG

proteus-js-client

Version:

Proteus JavaScript Client

262 lines (213 loc) 8.57 kB
/** * Copyright (c) 2017-present, Netifi Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * */ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProteusTcpConnection = undefined; var _RSocketFrame = require('rsocket-core/build/RSocketFrame'); var _tls = require('tls'); var _tls2 = _interopRequireDefault(_tls); var _rsocketFlowable = require('rsocket-flowable'); var _invariant = require('fbjs/lib/invariant'); var _invariant2 = _interopRequireDefault(_invariant); var _rsocketCore = require('rsocket-core'); var _rsocketTypes = require('rsocket-types'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * A TCP transport client for use in node environments. */ var ProteusTcpConnection = exports.ProteusTcpConnection = function () { function ProteusTcpConnection(socket, encoders) { var _this = this; _classCallCheck(this, ProteusTcpConnection); this._handleError = function (error) { _this._close(error || new Error('RSocketTcpClient: Socket closed unexpectedly.')); }; this._handleData = function (chunk) { try { var frames = _this._readFrames(chunk); frames.forEach(function (frame) { _this._receivers.forEach(function (subscriber) { return subscriber.onNext(frame); }); }); } catch (error) { _this._handleError(error); } }; this._buffer = (0, _rsocketCore.createBuffer)(0); this._encoders = encoders; this._receivers = new Set(); this._senders = new Set(); this._statusSubscribers = new Set(); if (socket) { this.setupSocket(socket); this._status = _rsocketTypes.CONNECTION_STATUS.CONNECTED; } else { this._socket = null; this._status = _rsocketTypes.CONNECTION_STATUS.NOT_CONNECTED; } } ProteusTcpConnection.prototype.close = function close() { this._close(); }; ProteusTcpConnection.prototype.connect = function connect() { throw new Error('not supported'); }; ProteusTcpConnection.prototype.setupSocket = function setupSocket(socket) { this._socket = socket; socket.on('close', this._handleError); socket.on('end', this._handleError); socket.on('error', this._handleError); socket.on('data', this._handleData); }; ProteusTcpConnection.prototype.connectionStatus = function connectionStatus() { var _this2 = this; return new _rsocketFlowable.Flowable(function (subscriber) { subscriber.onSubscribe({ cancel: function cancel() { _this2._statusSubscribers.delete(subscriber); }, request: function request() { _this2._statusSubscribers.add(subscriber); subscriber.onNext(_this2._status); } }); }); }; ProteusTcpConnection.prototype.receive = function receive() { var _this3 = this; return new _rsocketFlowable.Flowable(function (subject) { subject.onSubscribe({ cancel: function cancel() { _this3._receivers.delete(subject); }, request: function request() { _this3._receivers.add(subject); } }); }); }; ProteusTcpConnection.prototype.sendOne = function sendOne(frame) { this._writeFrame(frame); }; ProteusTcpConnection.prototype.send = function send(frames) { var _this4 = this; var subscription = void 0; frames.subscribe({ onComplete: function onComplete() { subscription && _this4._senders.delete(subscription); }, onError: function onError(error) { subscription && _this4._senders.delete(subscription); _this4._handleError(error); }, onNext: function onNext(frame) { return _this4._writeFrame(frame); }, onSubscribe: function onSubscribe(_subscription) { subscription = _subscription; _this4._senders.add(subscription); subscription.request(_RSocketFrame.MAX_REQUEST_N); } }); }; ProteusTcpConnection.prototype.getConnectionState = function getConnectionState() { return this._status; }; ProteusTcpConnection.prototype.setConnectionStatus = function setConnectionStatus(status) { this._status = status; this._statusSubscribers.forEach(function (subscriber) { return subscriber.onNext(status); }); }; ProteusTcpConnection.prototype._close = function _close(error) { if (this._status.kind === 'CLOSED' || this._status.kind === 'ERROR') { // already closed return; } var status = error ? { error: error, kind: 'ERROR' } : _rsocketTypes.CONNECTION_STATUS.CLOSED; this.setConnectionStatus(status); this._receivers.forEach(function (subscriber) { if (error) { subscriber.onError(error); } else { subscriber.onComplete(); } }); this._receivers.clear(); this._senders.forEach(function (subscription) { return subscription.cancel(); }); this._senders.clear(); var socket = this._socket; if (socket) { socket.removeAllListeners(); socket.end(); this._socket = null; } }; ProteusTcpConnection.prototype._readFrames = function _readFrames(chunk) { // Combine partial frame data from previous chunks with the next chunk, // then extract any complete frames plus any remaining data. var buffer = Buffer.concat([this._buffer, chunk]); var _deserializeFrames = (0, _rsocketCore.deserializeFrames)(buffer, this._encoders), frames = _deserializeFrames[0], remaining = _deserializeFrames[1]; this._buffer = remaining; return frames; }; ProteusTcpConnection.prototype._writeFrame = function _writeFrame(frame) { try { var buffer = (0, _rsocketCore.serializeFrameWithLength)(frame, this._encoders); (0, _invariant2.default)(this._socket, 'RSocketTcpClient: Cannot send frame, not connected.'); this._socket.write(buffer); } catch (error) { this._handleError(error); } }; return ProteusTcpConnection; }(); /** * A TLS transport client for use in node environments. */ var ProteusTlsClient = function (_ProteusTcpConnection) { _inherits(ProteusTlsClient, _ProteusTcpConnection); function ProteusTlsClient(options, encoders) { _classCallCheck(this, ProteusTlsClient); var _this5 = _possibleConstructorReturn(this, _ProteusTcpConnection.call(this, null, encoders)); _this5._handleOpened = function () { _this5.setConnectionStatus(_rsocketTypes.CONNECTION_STATUS.CONNECTED); }; _this5._options = options; return _this5; } ProteusTlsClient.prototype.connect = function connect() { (0, _invariant2.default)(this.getConnectionState().kind === 'NOT_CONNECTED', 'ProteusTlsClient: Cannot connect(), a connection is already ' + 'established.'); this.setConnectionStatus(_rsocketTypes.CONNECTION_STATUS.CONNECTING); var socket = _tls2.default.connect(this._options); this.setupSocket(socket); socket.on('connect', this._handleOpened); }; return ProteusTlsClient; }(ProteusTcpConnection); exports.default = ProteusTlsClient;