proteus-js-client
Version:
Proteus JavaScript Client
262 lines (213 loc) • 8.57 kB
JavaScript
/**
* 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.
*
*
*/
;
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;