'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _from = require('babel-runtime/core-js/array/from'); var _from2 = _interopRequireDefault(_from); var _defineProperty2 = require('babel-runtime/helpers/defineProperty'); var _defineProperty3 = _interopRequireDefault(_defineProperty2); var _stringify = require('babel-runtime/core-js/json/stringify'); var _stringify2 = _interopRequireDefault(_stringify); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _error = require('../error'); var _integer = require('../integer'); var _integer2 = _interopRequireDefault(_integer); var _serverVersion = require('./server-version'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var CALL_GET_SERVERS = 'CALL dbms.cluster.routing.getServers'; /** * 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 GET_ROUTING_TABLE_PARAM = 'context'; var CALL_GET_ROUTING_TABLE = 'CALL dbms.cluster.routing.getRoutingTable({' + GET_ROUTING_TABLE_PARAM + '})'; var PROCEDURE_NOT_FOUND_CODE = 'Neo.ClientError.Procedure.ProcedureNotFound'; var UNAUTHORIZED_CODE = 'Neo.ClientError.Security.Unauthorized'; var RoutingUtil = function () { function RoutingUtil(routingContext) { (0, _classCallCheck3.default)(this, RoutingUtil); this._routingContext = routingContext; } /** * Invoke routing procedure using the given session. * @param {Session} session the session to use. * @param {string} routerAddress the URL of the router. * @return {Promise} promise resolved with records returned by the procedure call or null if * connection error happened. */ (0, _createClass3.default)(RoutingUtil, [{ key: 'callRoutingProcedure', value: function callRoutingProcedure(session, routerAddress) { return this._callAvailableRoutingProcedure(session).then(function (result) { session.close(); return result.records; }).catch(function (error) { if (error.code === PROCEDURE_NOT_FOUND_CODE) { // throw when getServers procedure not found because this is clearly a configuration issue throw (0, _error.newError)('Server at ' + routerAddress + ' can\'t perform routing. Make sure you are connecting to a causal cluster', _error.SERVICE_UNAVAILABLE); } else if (error.code === UNAUTHORIZED_CODE) { // auth error is a sign of a configuration issue, rediscovery should not proceed throw error; } else { // return nothing when failed to connect because code higher in the callstack is still able to retry with a // different session towards a different router return null; } }); } }, { key: 'parseTtl', value: function parseTtl(record, routerAddress) { try { var now = (0, _integer.int)(Date.now()); var expires = record.get('ttl').multiply(1000).add(now); // if the server uses a really big expire time like Long.MAX_VALUE this may have overflowed if (expires.lessThan(now)) { return _integer2.default.MAX_VALUE; } return expires; } catch (error) { throw (0, _error.newError)('Unable to parse TTL entry from router ' + routerAddress + ' from record:\n' + (0, _stringify2.default)(record), _error.PROTOCOL_ERROR); } } }, { key: 'parseServers', value: function parseServers(record, routerAddress) { try { var servers = record.get('servers'); var routers = []; var readers = []; var writers = []; servers.forEach(function (server) { var role = server['role']; var addresses = server['addresses']; if (role === 'ROUTE') { routers = parseArray(addresses); } else if (role === 'WRITE') { writers = parseArray(addresses); } else if (role === 'READ') { readers = parseArray(addresses); } else { throw (0, _error.newError)('Unknown server role "' + role + '"', _error.PROTOCOL_ERROR); } }); return { routers: routers, readers: readers, writers: writers }; } catch (ignore) { throw (0, _error.newError)('Unable to parse servers entry from router ' + routerAddress + ' from record:\n' + (0, _stringify2.default)(record), _error.PROTOCOL_ERROR); } } }, { key: '_callAvailableRoutingProcedure', value: function _callAvailableRoutingProcedure(session) { var _this = this; return session._run(null, null, function (connection, streamObserver) { var serverVersionString = connection.server.version; var serverVersion = _serverVersion.ServerVersion.fromString(serverVersionString); if (serverVersion.compareTo(_serverVersion.VERSION_3_2_0) >= 0) { var params = (0, _defineProperty3.default)({}, GET_ROUTING_TABLE_PARAM, _this._routingContext); connection.run(CALL_GET_ROUTING_TABLE, params, streamObserver); } else { connection.run(CALL_GET_SERVERS, {}, streamObserver); } }); } }]); return RoutingUtil; }(); exports.default = RoutingUtil; function parseArray(addresses) { if (!Array.isArray(addresses)) { throw new TypeError('Array expected but got: ' + addresses); } return (0, _from2.default)(addresses); }