Skip to content

Commit fac5c0d

Browse files
committed
Merge branch '1.7' into 2.0
2 parents 3cfcfb7 + e66c4e8 commit fac5c0d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1737
-1106
lines changed

gulpfile.babel.js

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,27 @@
1717
* limitations under the License.
1818
*/
1919

20-
var browserify = require('browserify')
21-
var source = require('vinyl-source-stream')
22-
var buffer = require('vinyl-buffer')
23-
var gulp = require('gulp')
24-
var through = require('through2')
25-
var uglify = require('gulp-uglify')
26-
var jasmine = require('gulp-jasmine')
27-
var babelify = require('babelify')
28-
var babel = require('gulp-babel')
29-
var watch = require('gulp-watch')
30-
var batch = require('gulp-batch')
31-
var replace = require('gulp-replace')
32-
var fs = require('fs-extra')
33-
var path = require('path')
34-
var minimist = require('minimist')
35-
var install = require('gulp-install')
36-
var file = require('gulp-file')
37-
var semver = require('semver')
38-
var sharedNeo4j = require('./test/internal/shared-neo4j').default
39-
var ts = require('gulp-typescript')
40-
var JasmineConsoleReporter = require('jasmine-console-reporter')
41-
var karma = require('karma')
42-
var transformTools = require('browserify-transform-tools')
43-
var log = require('fancy-log')
20+
const browserify = require('browserify')
21+
const source = require('vinyl-source-stream')
22+
const buffer = require('vinyl-buffer')
23+
const gulp = require('gulp')
24+
const uglify = require('gulp-uglify')
25+
const jasmine = require('gulp-jasmine')
26+
const babel = require('gulp-babel')
27+
const watch = require('gulp-watch')
28+
const batch = require('gulp-batch')
29+
const replace = require('gulp-replace')
30+
const fs = require('fs-extra')
31+
const path = require('path')
32+
const minimist = require('minimist')
33+
const install = require('gulp-install')
34+
const file = require('gulp-file')
35+
const semver = require('semver')
36+
const sharedNeo4j = require('./test/internal/shared-neo4j').default
37+
const ts = require('gulp-typescript')
38+
const JasmineConsoleReporter = require('jasmine-console-reporter')
39+
const karma = require('karma')
40+
const log = require('fancy-log')
4441

4542
/**
4643
* Useful to investigate resource leaks in tests. Enable to see active sockets and file handles after the 'test' task.

src/driver.js

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ const DEFAULT_MAX_CONNECTION_LIFETIME = 60 * 60 * 1000 // 1 hour
3636

3737
/**
3838
* Constant that represents read session access mode.
39-
* Should be used like this: `driver.session(neo4j.session.READ)`.
39+
* Should be used like this: `driver.session({ defaultAccessMode: neo4j.session.READ })`.
4040
* @type {string}
4141
*/
4242
const READ = ACCESS_MODE_READ
4343

4444
/**
4545
* Constant that represents write session access mode.
46-
* Should be used like this: `driver.session(neo4j.session.WRITE)`.
46+
* Should be used like this: `driver.session({ defaultAccessMode: neo4j.session.WRITE })`.
4747
* @type {string}
4848
*/
4949
const WRITE = ACCESS_MODE_WRITE
@@ -64,17 +64,17 @@ class Driver {
6464
/**
6565
* You should not be calling this directly, instead use {@link driver}.
6666
* @constructor
67-
* @param {string} hostPort
67+
* @param {ServerAddress} address
6868
* @param {string} userAgent
6969
* @param {object} authToken
7070
* @param {object} config
7171
* @protected
7272
*/
73-
constructor (hostPort, userAgent, authToken = {}, config = {}) {
73+
constructor (address, userAgent, authToken = {}, config = {}) {
7474
sanitizeConfig(config)
7575

7676
this._id = idGenerator++
77-
this._hostPort = hostPort
77+
this._address = address
7878
this._userAgent = userAgent
7979
this._openConnections = {}
8080
this._authToken = authToken
@@ -103,7 +103,7 @@ class Driver {
103103
*/
104104
_afterConstruction () {
105105
this._log.info(
106-
`Direct driver ${this._id} created for server address ${this._hostPort}`
106+
`Direct driver ${this._id} created for server address ${this._address}`
107107
)
108108
}
109109

@@ -123,21 +123,23 @@ class Driver {
123123
* @return {Promise<Connection>} promise resolved with a new connection or rejected when failed to connect.
124124
* @access private
125125
*/
126-
_createConnection (hostPort, release) {
126+
_createConnection (address, release) {
127127
const connection = Connection.create(
128-
hostPort,
128+
address,
129129
this._config,
130130
this._createConnectionErrorHandler(),
131131
this._log
132132
)
133-
connection._release = () => release(hostPort, connection)
133+
connection._release = () => release(address, connection)
134134
this._openConnections[connection.id] = connection
135135

136136
return connection.connect(this._userAgent, this._authToken).catch(error => {
137137
if (this.onError) {
138138
// notify Driver.onError callback about connection initialization errors
139139
this.onError(error)
140140
}
141+
// let's destroy this connection
142+
this._destroyConnection(connection)
141143
// propagate the error because connection failed to connect / initialize
142144
throw error
143145
})
@@ -213,9 +215,9 @@ class Driver {
213215
}
214216

215217
// Extension point
216-
_createConnectionProvider (hostPort, connectionPool, driverOnErrorCallback) {
218+
_createConnectionProvider (address, connectionPool, driverOnErrorCallback) {
217219
return new DirectConnectionProvider(
218-
hostPort,
220+
address,
219221
connectionPool,
220222
driverOnErrorCallback
221223
)
@@ -230,7 +232,7 @@ class Driver {
230232
if (!this._connectionProvider) {
231233
const driverOnErrorCallback = this._driverOnErrorCallback.bind(this)
232234
this._connectionProvider = this._createConnectionProvider(
233-
this._hostPort,
235+
this._address,
234236
this._pool,
235237
driverOnErrorCallback
236238
)

src/index.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
LocalTime,
5656
Time
5757
} from './temporal-types'
58+
import ServerAddress from './internal/server-address'
5859

5960
/**
6061
* @property {function(username: string, password: string, realm: ?string)} basic the function to create a
@@ -241,7 +242,7 @@ function driver (url, authToken, config = {}) {
241242
const parsedUrl = urlUtil.parseDatabaseUrl(url)
242243
if (parsedUrl.scheme === 'neo4j') {
243244
return new RoutingDriver(
244-
parsedUrl.hostAndPort,
245+
ServerAddress.fromUrl(parsedUrl.hostAndPort),
245246
parsedUrl.query,
246247
USER_AGENT,
247248
authToken,
@@ -253,7 +254,12 @@ function driver (url, authToken, config = {}) {
253254
`Parameters are not supported with scheme 'bolt'. Given URL: '${url}'`
254255
)
255256
}
256-
return new Driver(parsedUrl.hostAndPort, USER_AGENT, authToken, config)
257+
return new Driver(
258+
ServerAddress.fromUrl(parsedUrl.hostAndPort),
259+
USER_AGENT,
260+
authToken,
261+
config
262+
)
257263
} else if (parsedUrl.scheme === 'http' || parsedUrl.scheme === 'https') {
258264
return new HttpDriver(parsedUrl, USER_AGENT, authToken, config)
259265
} else {

src/internal/browser/browser-channel.js

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export default class WebSocketChannel {
4444
return
4545
}
4646

47-
this._ws = createWebSocket(scheme, config.url)
47+
this._ws = createWebSocket(scheme, config.address)
4848
this._ws.binaryType = 'arraybuffer'
4949

5050
let self = this
@@ -174,13 +174,13 @@ export default class WebSocketChannel {
174174
}
175175
}
176176

177-
function createWebSocket (scheme, parsedUrl) {
178-
const url = scheme + '://' + parsedUrl.hostAndPort
177+
function createWebSocket (scheme, address) {
178+
const url = scheme + '://' + address.asHostPort()
179179

180180
try {
181181
return new WebSocket(url)
182182
} catch (error) {
183-
if (isIPv6AddressIssueOnWindows(error, parsedUrl)) {
183+
if (isIPv6AddressIssueOnWindows(error, address)) {
184184
// WebSocket in IE and Edge browsers on Windows do not support regular IPv6 address syntax because they contain ':'.
185185
// It's an invalid character for UNC (https://en.wikipedia.org/wiki/IPv6_address#Literal_IPv6_addresses_in_UNC_path_names)
186186
// and Windows requires IPv6 to be changes in the following way:
@@ -194,34 +194,33 @@ function createWebSocket (scheme, parsedUrl) {
194194
// Creation of WebSocket with unconverted address results in SyntaxError without message or stacktrace.
195195
// That is why here we "catch" SyntaxError and rewrite IPv6 address if needed.
196196

197-
const windowsFriendlyUrl = asWindowsFriendlyIPv6Address(scheme, parsedUrl)
197+
const windowsFriendlyUrl = asWindowsFriendlyIPv6Address(scheme, address)
198198
return new WebSocket(windowsFriendlyUrl)
199199
} else {
200200
throw error
201201
}
202202
}
203203
}
204204

205-
function isIPv6AddressIssueOnWindows (error, parsedUrl) {
206-
return error.name === 'SyntaxError' && isIPv6Address(parsedUrl)
205+
function isIPv6AddressIssueOnWindows (error, address) {
206+
return error.name === 'SyntaxError' && isIPv6Address(address.asHostPort())
207207
}
208208

209-
function isIPv6Address (parsedUrl) {
210-
const hostAndPort = parsedUrl.hostAndPort
209+
function isIPv6Address (hostAndPort) {
211210
return hostAndPort.charAt(0) === '[' && hostAndPort.indexOf(']') !== -1
212211
}
213212

214-
function asWindowsFriendlyIPv6Address (scheme, parsedUrl) {
213+
function asWindowsFriendlyIPv6Address (scheme, address) {
215214
// replace all ':' with '-'
216-
const hostWithoutColons = parsedUrl.host.replace(new RegExp(':', 'g'), '-')
215+
const hostWithoutColons = address.host().replace(new RegExp(':', 'g'), '-')
217216

218217
// replace '%' with 's' for link-local IPv6 address like 'fe80::1%lo0'
219218
const hostWithoutPercent = hostWithoutColons.replace('%', 's')
220219

221220
// append magic '.ipv6-literal.net' suffix
222221
const ipv6Host = hostWithoutPercent + '.ipv6-literal.net'
223222

224-
return `${scheme}://${ipv6Host}:${parsedUrl.port}`
223+
return `${scheme}://${ipv6Host}:${address.port()}`
225224
}
226225

227226
/**

src/internal/channel-config.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ const ALLOWED_VALUES_TRUST = [
4242
export default class ChannelConfig {
4343
/**
4444
* @constructor
45-
* @param {Url} url the URL for the channel to connect to.
45+
* @param {ServerAddress} address the address for the channel to connect to.
4646
* @param {object} driverConfig the driver config provided by the user when driver is created.
4747
* @param {string} connectionErrorCode the default error code to use on connection errors.
4848
*/
49-
constructor (url, driverConfig, connectionErrorCode) {
50-
this.url = url
49+
constructor (address, driverConfig, connectionErrorCode) {
50+
this.address = address
5151
this.encrypted = extractEncrypted(driverConfig)
5252
this.trust = extractTrust(driverConfig)
5353
this.trustedCertificates = extractTrustedCertificates(driverConfig)

src/internal/connection-error-handler.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ export default class ConnectionErrorHandler {
3737
/**
3838
* Handle and transform the error.
3939
* @param {Neo4jError} error the original error.
40-
* @param {string} hostPort the host and port of the connection where the error happened.
40+
* @param {ServerAddress} address the address of the connection where the error happened.
4141
* @return {Neo4jError} new error that should be propagated to the user.
4242
*/
43-
handleAndTransformError (error, hostPort) {
43+
handleAndTransformError (error, address) {
4444
if (isAvailabilityError(error)) {
45-
return this._handleUnavailability(error, hostPort)
45+
return this._handleUnavailability(error, address)
4646
}
4747
if (isFailureToWrite(error)) {
48-
return this._handleWriteFailure(error, hostPort)
48+
return this._handleWriteFailure(error, address)
4949
}
5050
return error
5151
}

src/internal/connection-providers.js

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import Session from '../session'
2323
import RoutingTable from './routing-table'
2424
import Rediscovery from './rediscovery'
2525
import RoutingUtil from './routing-util'
26+
import { HostNameResolver } from './node'
2627

2728
const UNAUTHORIZED_ERROR_CODE = 'Neo.ClientError.Security.Unauthorized'
2829

@@ -43,15 +44,15 @@ class ConnectionProvider {
4344
}
4445

4546
export class DirectConnectionProvider extends ConnectionProvider {
46-
constructor (hostPort, connectionPool, driverOnErrorCallback) {
47+
constructor (address, connectionPool, driverOnErrorCallback) {
4748
super()
48-
this._hostPort = hostPort
49+
this._address = address
4950
this._connectionPool = connectionPool
5051
this._driverOnErrorCallback = driverOnErrorCallback
5152
}
5253

5354
acquireConnection (accessMode, db) {
54-
const connectionPromise = this._connectionPool.acquire(this._hostPort)
55+
const connectionPromise = this._connectionPool.acquire(this._address)
5556
return this._withAdditionalOnErrorCallback(
5657
connectionPromise,
5758
this._driverOnErrorCallback
@@ -61,7 +62,7 @@ export class DirectConnectionProvider extends ConnectionProvider {
6162

6263
export class LoadBalancer extends ConnectionProvider {
6364
constructor (
64-
hostPort,
65+
address,
6566
routingContext,
6667
connectionPool,
6768
loadBalancingStrategy,
@@ -70,15 +71,16 @@ export class LoadBalancer extends ConnectionProvider {
7071
log
7172
) {
7273
super()
73-
this._seedRouter = hostPort
74-
this._routingTable = new RoutingTable([this._seedRouter])
74+
this._seedRouter = address
75+
this._routingTable = new RoutingTable()
7576
this._rediscovery = new Rediscovery(new RoutingUtil(routingContext))
7677
this._connectionPool = connectionPool
7778
this._driverOnErrorCallback = driverOnErrorCallback
7879
this._loadBalancingStrategy = loadBalancingStrategy
7980
this._hostNameResolver = hostNameResolver
81+
this._dnsResolver = new HostNameResolver()
8082
this._log = log
81-
this._useSeedRouter = false
83+
this._useSeedRouter = true
8284
}
8385

8486
acquireConnection (accessMode, db) {
@@ -238,6 +240,20 @@ export class LoadBalancer extends ConnectionProvider {
238240
})
239241
}
240242

243+
_resolveSeedRouter (seedRouter) {
244+
const customResolution = this._hostNameResolver.resolve(seedRouter)
245+
const dnsResolutions = customResolution.then(resolvedAddresses => {
246+
return Promise.all(
247+
resolvedAddresses.map(address => {
248+
return this._dnsResolver.resolve(address)
249+
})
250+
)
251+
})
252+
return dnsResolutions.then(results => {
253+
return [].concat.apply([], results)
254+
})
255+
}
256+
241257
_fetchRoutingTable (routerAddresses, routingTable) {
242258
return routerAddresses.reduce(
243259
(refreshedTablePromise, currentRouter, currentIndex) => {
@@ -260,10 +276,14 @@ export class LoadBalancer extends ConnectionProvider {
260276
return this._createSessionForRediscovery(currentRouter).then(
261277
session => {
262278
if (session) {
263-
return this._rediscovery.lookupRoutingTableOnRouter(
264-
session,
265-
currentRouter
266-
)
279+
return this._rediscovery
280+
.lookupRoutingTableOnRouter(session, currentRouter)
281+
.catch(error => {
282+
this._log.warn(
283+
`unable to fetch routing table because of an error ${error}`
284+
)
285+
return null
286+
})
267287
} else {
268288
// unable to acquire connection and create session towards the current router
269289
// return null to signal that the next router should be tried
@@ -315,11 +335,8 @@ export class LoadBalancer extends ConnectionProvider {
315335
}
316336

317337
_updateRoutingTable (newRoutingTable) {
318-
const currentRoutingTable = this._routingTable
319-
320338
// close old connections to servers not present in the new routing table
321-
const staleServers = currentRoutingTable.serversDiff(newRoutingTable)
322-
staleServers.forEach(server => this._connectionPool.purge(server))
339+
this._connectionPool.keepAll(newRoutingTable.allServers())
323340

324341
// make this driver instance aware of the new table
325342
this._routingTable = newRoutingTable

0 commit comments

Comments
 (0)