'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.WRITE = exports.READ = exports.Driver = undefined; var _maxSafeInteger = require('babel-runtime/core-js/number/max-safe-integer'); var _maxSafeInteger2 = _interopRequireDefault(_maxSafeInteger); var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _get2 = require('babel-runtime/helpers/get'); var _get3 = _interopRequireDefault(_get2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _session = require('./session'); var _session2 = _interopRequireDefault(_session); var _pool = require('./internal/pool'); var _pool2 = _interopRequireDefault(_pool); var _connector = require('./internal/connector'); var _streamObserver = require('./internal/stream-observer'); var _streamObserver2 = _interopRequireDefault(_streamObserver); var _error = require('./error'); var _connectionProviders = require('./internal/connection-providers'); var _bookmark = require('./internal/bookmark'); var _bookmark2 = _interopRequireDefault(_bookmark); var _connectivityVerifier = require('./internal/connectivity-verifier'); var _connectivityVerifier2 = _interopRequireDefault(_connectivityVerifier); var _poolConfig = require('./internal/pool-config'); var _poolConfig2 = _interopRequireDefault(_poolConfig); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var DEFAULT_MAX_CONNECTION_LIFETIME = 60 * 60 * 1000; // 1 hour /** * Constant that represents read session access mode. * Should be used like this: driver.session(READ). * @type {string} */ /** * Copyright (c) 2002-2018 "Neo4j," * Neo4j Sweden AB [http://neo4j.com] * * This file is part of Neo4j. * * 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. */ var READ = 'READ'; /** * Constant that represents write session access mode. * Should be used like this: driver.session(WRITE). * @type {string} */ var WRITE = 'WRITE'; /** * A driver maintains one or more {@link Session}s with a remote * Neo4j instance. Through the {@link Session}s you can send statements * and retrieve results from the database. * * Drivers are reasonably expensive to create - you should strive to keep one * driver instance around per Neo4j Instance you connect to. * * @access public */ var Driver = function () { /** * You should not be calling this directly, instead use {@link driver}. * @constructor * @param {string} hostPort * @param {string} userAgent * @param {object} token * @param {object} config * @protected */ function Driver(hostPort, userAgent) { var token = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var config = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; (0, _classCallCheck3.default)(this, Driver); sanitizeConfig(config); this._hostPort = hostPort; this._userAgent = userAgent; this._openSessions = {}; this._sessionIdGenerator = 0; this._token = token; this._config = config; this._pool = new _pool2.default(this._createConnection.bind(this), this._destroyConnection.bind(this), this._validateConnection.bind(this), _poolConfig2.default.fromDriverConfig(config)); /** * Reference to the connection provider. Initialized lazily by {@link _getOrCreateConnectionProvider}. * @type {ConnectionProvider} * @protected */ this._connectionProvider = null; this._onCompleted = null; } /** * Get the installed connectivity verification callback. * @return {null|function} * @deprecated driver can be used directly once instantiated, use of this callback is not required. */ (0, _createClass3.default)(Driver, [{ key: '_createConnection', /** * Create a new connection instance. * @return {Connection} new connector-api session instance, a low level session API. * @access private */ value: function _createConnection(hostPort, release) { var sessionId = this._sessionIdGenerator++; var conn = (0, _connector.connect)(hostPort, this._config, this._connectionErrorCode()); var streamObserver = new _ConnectionStreamObserver(this, conn); conn.initialize(this._userAgent, this._token, streamObserver); conn._id = sessionId; conn._release = function () { return release(hostPort, conn); }; this._openSessions[sessionId] = conn; return conn; } /** * Check that a connection is usable * @return {boolean} true if the connection is open * @access private **/ }, { key: '_validateConnection', value: function _validateConnection(conn) { if (!conn.isOpen()) { return false; } var maxConnectionLifetime = this._config.maxConnectionLifetime; var lifetime = Date.now() - conn.creationTimestamp; return lifetime <= maxConnectionLifetime; } /** * Dispose of a live session, closing any associated resources. * @return {Session} new session. * @access private */ }, { key: '_destroyConnection', value: function _destroyConnection(conn) { delete this._openSessions[conn._id]; conn.close(); } /** * Acquire a session to communicate with the database. The driver maintains * a pool of sessions, so calling this method is normally cheap because you * will be pulling a session out of the common pool. * * This comes with some responsibility - make sure you always call * {@link close} when you are done using a session, and likewise, * make sure you don't close your session before you are done using it. Once * it is returned to the pool, the session will be reset to a clean state and * made available for others to use. * * @param {string} [mode=WRITE] the access mode of this session, allowed values are {@link READ} and {@link WRITE}. * @param {string|string[]} [bookmarkOrBookmarks=null] the initial reference or references to some previous * transactions. Value is optional and absence indicates that that the bookmarks do not exist or are unknown. * @return {Session} new session. */ }, { key: 'session', value: function session(mode, bookmarkOrBookmarks) { var sessionMode = Driver._validateSessionMode(mode); var connectionProvider = this._getOrCreateConnectionProvider(); var bookmark = new _bookmark2.default(bookmarkOrBookmarks); return this._createSession(sessionMode, connectionProvider, bookmark, this._config); } }, { key: '_createConnectionProvider', // Extension point value: function _createConnectionProvider(hostPort, connectionPool, driverOnErrorCallback) { return new _connectionProviders.DirectConnectionProvider(hostPort, connectionPool, driverOnErrorCallback); } // Extension point }, { key: '_createSession', value: function _createSession(mode, connectionProvider, bookmark, config) { return new _session2.default(mode, connectionProvider, bookmark, config); } // Extension point }, { key: '_connectionErrorCode', value: function _connectionErrorCode() { // connection errors might result in different error codes depending on the driver return _error.SERVICE_UNAVAILABLE; } }, { key: '_getOrCreateConnectionProvider', value: function _getOrCreateConnectionProvider() { if (!this._connectionProvider) { var driverOnErrorCallback = this._driverOnErrorCallback.bind(this); this._connectionProvider = this._createConnectionProvider(this._hostPort, this._pool, driverOnErrorCallback); } return this._connectionProvider; } }, { key: '_driverOnErrorCallback', value: function _driverOnErrorCallback(error) { var userDefinedOnErrorCallback = this.onError; if (userDefinedOnErrorCallback && error.code === _error.SERVICE_UNAVAILABLE) { userDefinedOnErrorCallback(error); } else { // we don't need to tell the driver about this error } } /** * Close all open sessions and other associated resources. You should * make sure to use this when you are done with this driver instance. * @return undefined */ }, { key: 'close', value: function close() { for (var sessionId in this._openSessions) { if (this._openSessions.hasOwnProperty(sessionId)) { this._openSessions[sessionId].close(); } this._pool.purgeAll(); } } }, { key: 'onCompleted', get: function get() { return this._onCompleted; } /** * Install a connectivity verification callback. * @param {null|function} callback the new function to be notified about successful connection. * @deprecated driver can be used directly once instantiated, use of this callback is not required. */ , set: function set(callback) { this._onCompleted = callback; if (this._onCompleted) { var connectionProvider = this._getOrCreateConnectionProvider(); var connectivityVerifier = new _connectivityVerifier2.default(connectionProvider, this._onCompleted); connectivityVerifier.verify(); } } }], [{ key: '_validateSessionMode', value: function _validateSessionMode(rawMode) { var mode = rawMode || WRITE; if (mode !== READ && mode !== WRITE) { throw (0, _error.newError)('Illegal session mode ' + mode); } return mode; } }]); return Driver; }(); /** Internal stream observer used for connection state */ var _ConnectionStreamObserver = function (_StreamObserver) { (0, _inherits3.default)(_ConnectionStreamObserver, _StreamObserver); function _ConnectionStreamObserver(driver, conn) { (0, _classCallCheck3.default)(this, _ConnectionStreamObserver); var _this = (0, _possibleConstructorReturn3.default)(this, (_ConnectionStreamObserver.__proto__ || (0, _getPrototypeOf2.default)(_ConnectionStreamObserver)).call(this)); _this._driver = driver; _this._conn = conn; _this._hasFailed = false; return _this; } (0, _createClass3.default)(_ConnectionStreamObserver, [{ key: 'onError', value: function onError(error) { if (!this._hasFailed) { (0, _get3.default)(_ConnectionStreamObserver.prototype.__proto__ || (0, _getPrototypeOf2.default)(_ConnectionStreamObserver.prototype), 'onError', this).call(this, error); if (this._driver.onError) { this._driver.onError(error); } this._hasFailed = true; } } }]); return _ConnectionStreamObserver; }(_streamObserver2.default); /** * @private */ function sanitizeConfig(config) { config.maxConnectionLifetime = sanitizeIntValue(config.maxConnectionLifetime, DEFAULT_MAX_CONNECTION_LIFETIME); config.maxConnectionPoolSize = sanitizeIntValue(config.maxConnectionPoolSize, _poolConfig.DEFAULT_MAX_SIZE); config.connectionAcquisitionTimeout = sanitizeIntValue(config.connectionAcquisitionTimeout, _poolConfig.DEFAULT_ACQUISITION_TIMEOUT); } function sanitizeIntValue(rawValue, defaultWhenAbsent) { var sanitizedValue = parseInt(rawValue, 10); if (sanitizedValue > 0 || sanitizedValue === 0) { return sanitizedValue; } else if (sanitizedValue < 0) { return _maxSafeInteger2.default; } else { return defaultWhenAbsent; } } exports.Driver = Driver; exports.READ = READ; exports.WRITE = WRITE; exports.default = Driver;