Skip to content

Commit 652ac1b

Browse files
Introduce neo4j.hasReachableServer API
This is an experimental API responsible for verifying if the given url is running a Neo4j Server. Co-Authored-by: Oskar Damkjaer <OskarDamkjaer@users.noreply.github.com>
1 parent c6164d7 commit 652ac1b

File tree

9 files changed

+112
-0
lines changed

9 files changed

+112
-0
lines changed

packages/bolt-connection/src/connection-provider/connection-provider-direct.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ export default class DirectConnectionProvider extends PooledConnectionProvider {
9292
)
9393
}
9494

95+
getNegotiatedProtocolVersion () {
96+
return new Promise((resolve, reject) => {
97+
this._hasProtocolVersion(resolve)
98+
.catch(reject)
99+
})
100+
}
101+
95102
async supportsTransactionConfig () {
96103
return await this._hasProtocolVersion(
97104
version => version >= BOLT_PROTOCOL_V3

packages/bolt-connection/src/connection-provider/connection-provider-routing.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,13 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
244244
)
245245
}
246246

247+
getNegotiatedProtocolVersion () {
248+
return new Promise((resolve, reject) => {
249+
this._hasProtocolVersion(resolve)
250+
.catch(reject)
251+
})
252+
}
253+
247254
async verifyConnectivityAndGetServerInfo ({ database, accessMode }) {
248255
const context = { database: database || DEFAULT_DB_NAME }
249256

packages/core/src/connection-provider.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@ class ConnectionProvider {
9898
throw Error('Not implemented')
9999
}
100100

101+
/**
102+
* Returns the protocol version negotiated via handshake.
103+
*
104+
* Note that this function call _always_ causes a round-trip to the server.
105+
*
106+
* @returns {Promise<number>} the protocol version negotiated via handshake.
107+
* @throws {Error} When protocol negotiation fails
108+
*/
109+
getNegotiatedProtocolVersion (): Promise<number> {
110+
throw Error('Not Implemented')
111+
}
112+
101113
/**
102114
* Closes this connection provider along with its internals (connections, pools, etc.)
103115
*

packages/core/src/driver.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,19 @@ class Driver {
220220
return connectionProvider.supportsUserImpersonation()
221221
}
222222

223+
/**
224+
* Returns the protocol version negotiated via handshake.
225+
*
226+
* Note that this function call _always_ causes a round-trip to the server.
227+
*
228+
* @returns {Promise<number>} the protocol version negotiated via handshake.
229+
* @throws {Error} When protocol negotiation fails
230+
*/
231+
getNegotiatedProtocolVersion (): Promise<number> {
232+
const connectionProvider = this._getOrCreateConnectionProvider()
233+
return connectionProvider.getNegotiatedProtocolVersion()
234+
}
235+
223236
/**
224237
* Returns boolean to indicate if driver has been configured with encryption enabled.
225238
*

packages/neo4j-driver-lite/src/index.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,26 @@ function driver (
328328
}
329329
}
330330

331+
/**
332+
* Method which veirfies if the driver is server is reachable.
333+
*
334+
* @experimental
335+
* @since 5.0.0
336+
* @param {string} url The URL for the Neo4j database, for instance "neo4j://localhost" and/or "bolt://localhost"
337+
* @param {Pick<Config, 'logging'>} config Configuration object. See the {@link driver}
338+
* @returns {true} When the server is reachable
339+
* @throws {Error} When the server is not reacheable or the url is invalid
340+
*/
341+
async function hasReachableServer (url: string, config?: Pick<Config, 'logging'>): Promise<true> {
342+
const nonLoggedDriver = driver(url, { scheme: 'none', principal: '', credentials: '' }, config)
343+
try {
344+
await nonLoggedDriver.getNegotiatedProtocolVersion()
345+
return true
346+
} finally {
347+
await nonLoggedDriver.close()
348+
}
349+
}
350+
331351
const USER_AGENT: string = 'neo4j-javascript/' + VERSION
332352

333353
/**
@@ -393,6 +413,7 @@ const temporal = {
393413
*/
394414
const forExport = {
395415
driver,
416+
hasReachableServer,
396417
int,
397418
isInt,
398419
isPoint,
@@ -444,6 +465,7 @@ const forExport = {
444465

445466
export {
446467
driver,
468+
hasReachableServer,
447469
int,
448470
isInt,
449471
isPoint,

packages/neo4j-driver-lite/test/integration/driver.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,12 @@ describe('neo4j-driver-lite', () => {
4545
expect(result.records[0].length).toEqual(1)
4646
result.records[0].forEach(val => expect(val).toEqual(int(2)))
4747
})
48+
49+
test('hasReachableServer success', async () => {
50+
await expect(neo4j.hasReachableServer(`${scheme}://${hostname}`)).resolves.toBe(true)
51+
})
52+
53+
test('hasReachableServer failure', async () => {
54+
await expect(neo4j.hasReachableServer(`${scheme}://${hostname}:9999`)).rejects.toBeInstanceOf(Error)
55+
})
4856
})

packages/neo4j-driver/src/index.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,26 @@ function driver (url, authToken, config = {}) {
305305
}
306306
}
307307

308+
/**
309+
* Method which veirfies if the driver is server is reachable.
310+
*
311+
* @experimental
312+
* @since 5.0.0
313+
* @param {string} url The URL for the Neo4j database, for instance "neo4j://localhost" and/or "bolt://localhost"
314+
* @param {object} config Configuration object. See the {@link driver}
315+
* @returns {true} When the server is reachable
316+
* @throws {Error} When the server is not reacheable or the url is invalid
317+
*/
318+
async function hasReachableServer (url, config) {
319+
const nonLoggedDriver = driver(url, { scheme: 'none', principal: '', credentials: '' }, config)
320+
try {
321+
await nonLoggedDriver.getNegotiatedProtocolVersion()
322+
return true
323+
} finally {
324+
await nonLoggedDriver.close()
325+
}
326+
}
327+
308328
const USER_AGENT = 'neo4j-javascript/' + VERSION
309329

310330
/**
@@ -385,6 +405,7 @@ const temporal = {
385405
*/
386406
const forExport = {
387407
driver,
408+
hasReachableServer,
388409
int,
389410
isInt,
390411
isPoint,
@@ -437,6 +458,7 @@ const forExport = {
437458

438459
export {
439460
driver,
461+
hasReachableServer,
440462
int,
441463
isInt,
442464
isPoint,

packages/neo4j-driver/test/driver.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,20 @@ describe('#integration driver', () => {
588588
})
589589
})
590590

591+
it('hasReachableServer success', async () => {
592+
const result = neo4j.hasReachableServer(`${sharedNeo4j.scheme}://${sharedNeo4j.hostname}`)
593+
expect(result).toBe(true)
594+
})
595+
596+
it('hasReachableServer failure', async () => {
597+
try {
598+
await neo4j.hasReachableServer(`${sharedNeo4j.scheme}://${sharedNeo4j.hostname}:9999`)
599+
expect(true).toBe('false')
600+
} catch (error) {
601+
expect(error).toBeInstanceOf(Error)
602+
}
603+
})
604+
591605
const integersWithNativeNumberEquivalent = [
592606
[neo4j.int(0), 0],
593607
[neo4j.int(42), 42],

packages/neo4j-driver/types/index.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ declare function driver (
100100
config?: Config
101101
): Driver
102102

103+
declare function hasReachableServer (
104+
url: string,
105+
config?: Pick<Config, 'logging'>
106+
): Promise<true>
107+
103108
declare const types: {
104109
Node: typeof Node
105110
Relationship: typeof Relationship
@@ -158,6 +163,7 @@ declare const temporal: {
158163

159164
declare const forExport: {
160165
driver: typeof driver
166+
hasReachableServer: typeof hasReachableServer
161167
int: typeof int
162168
isInt: typeof isInt
163169
integer: typeof integer
@@ -218,6 +224,7 @@ declare const forExport: {
218224

219225
export {
220226
driver,
227+
hasReachableServer,
221228
int,
222229
isInt,
223230
integer,

0 commit comments

Comments
 (0)