20
20
import Session from './session' ;
21
21
import Pool from './internal/pool' ;
22
22
import Integer from './integer' ;
23
- import { connect , parseScheme , parseUrl } from "./internal/connector" ;
23
+ import { connect } from "./internal/connector" ;
24
24
import StreamObserver from './internal/stream-observer' ;
25
- import VERSION from '../version' ;
26
- import { newError , SERVICE_UNAVAILABLE , SESSION_EXPIRED } from "./error" ;
25
+ import { newError } from "./error" ;
27
26
import "babel-polyfill" ;
28
27
29
28
let READ = 'READ' , WRITE = 'WRITE' ;
@@ -157,203 +156,6 @@ class Driver {
157
156
}
158
157
}
159
158
160
- class RoundRobinArray {
161
- constructor ( items ) {
162
- this . _items = items || [ ] ;
163
- this . _index = 0 ;
164
- }
165
-
166
- hop ( ) {
167
- let elem = this . _items [ this . _index ] ;
168
- if ( this . _items . length === 0 ) {
169
- this . _index = 0 ;
170
- } else {
171
- this . _index = ( this . _index + 1 ) % ( this . _items . length ) ;
172
- }
173
- return elem ;
174
- }
175
-
176
- push ( elem ) {
177
- this . _items . push ( elem ) ;
178
- }
179
-
180
- pushAll ( elems ) {
181
- Array . prototype . push . apply ( this . _items , elems ) ;
182
- }
183
-
184
- empty ( ) {
185
- return this . _items . length === 0 ;
186
- }
187
-
188
- clear ( ) {
189
- this . _items = [ ] ;
190
- this . _index = 0 ;
191
- }
192
-
193
- size ( ) {
194
- return this . _items . length ;
195
- }
196
-
197
- toArray ( ) {
198
- return this . _items ;
199
- }
200
-
201
- remove ( item ) {
202
- let index = this . _items . indexOf ( item ) ;
203
- while ( index != - 1 ) {
204
- this . _items . splice ( index , 1 ) ;
205
- if ( index < this . _index ) {
206
- this . _index -= 1 ;
207
- }
208
- //make sure we are in range
209
- if ( this . _items . length === 0 ) {
210
- this . _index = 0 ;
211
- } else {
212
- this . _index %= this . _items . length ;
213
- }
214
- }
215
- }
216
- }
217
-
218
- let GET_SERVERS = "CALL dbms.cluster.routing.getServers" ;
219
-
220
- class ClusterView {
221
- constructor ( routers , readers , writers , expires ) {
222
- this . routers = routers || new RoundRobinArray ( ) ;
223
- this . readers = readers || new RoundRobinArray ( ) ;
224
- this . writers = writers || new RoundRobinArray ( ) ;
225
- this . _expires = expires || - 1 ;
226
-
227
- }
228
-
229
- needsUpdate ( ) {
230
- return this . _expires < Date . now ( ) ||
231
- this . routers . empty ( ) ||
232
- this . readers . empty ( ) ||
233
- this . writers . empty ( ) ;
234
- }
235
-
236
- all ( ) {
237
- let seen = new Set ( this . routers . toArray ( ) ) ;
238
- let writers = this . writers . toArray ( ) ;
239
- let readers = this . readers . toArray ( ) ;
240
- for ( let i = 0 ; i < writers . length ; i ++ ) {
241
- seen . add ( writers [ i ] ) ;
242
- }
243
- for ( let i = 0 ; i < readers . length ; i ++ ) {
244
- seen . add ( readers [ i ] ) ;
245
- }
246
- return seen ;
247
- }
248
-
249
- remove ( item ) {
250
- this . routers . remove ( item ) ;
251
- this . readers . remove ( item ) ;
252
- this . writers . remove ( item ) ;
253
- }
254
- }
255
-
256
- function newClusterView ( session ) {
257
- return session . run ( GET_SERVERS )
258
- . then ( ( res ) => {
259
- session . close ( ) ;
260
- if ( res . records . length != 1 ) {
261
- return Promise . reject ( newError ( "Invalid routing response from server" , SERVICE_UNAVAILABLE ) ) ;
262
- }
263
- let record = res . records [ 0 ] ;
264
- //Note we are loosing precision here but let's hope that in
265
- //the 140000 years to come before this precision loss
266
- //hits us, that we get native 64 bit integers in javascript
267
- let expires = record . get ( 'ttl' ) . toNumber ( ) ;
268
- let servers = record . get ( 'servers' ) ;
269
- let routers = new RoundRobinArray ( ) ;
270
- let readers = new RoundRobinArray ( ) ;
271
- let writers = new RoundRobinArray ( ) ;
272
- for ( let i = 0 ; i < servers . length ; i ++ ) {
273
- let server = servers [ i ] ;
274
-
275
- let role = server [ 'role' ] ;
276
- let addresses = server [ 'addresses' ] ;
277
- if ( role === 'ROUTE' ) {
278
- routers . pushAll ( addresses ) ;
279
- } else if ( role === 'WRITE' ) {
280
- writers . pushAll ( addresses ) ;
281
- } else if ( role === 'READ' ) {
282
- readers . pushAll ( addresses ) ;
283
- }
284
- }
285
- return new ClusterView ( routers , readers , writers , expires ) ;
286
- } ) ;
287
- }
288
-
289
- class RoutingDriver extends Driver {
290
-
291
- constructor ( url , userAgent = 'neo4j-javascript/0.0' , token = { } , config = { } ) {
292
- super ( url , userAgent , token , config ) ;
293
- this . _clusterView = new ClusterView ( new RoundRobinArray ( [ parseUrl ( url ) ] ) ) ;
294
- }
295
-
296
- session ( mode ) {
297
- let conn = this . _acquireConnection ( mode ) ;
298
- return this . _createSession ( conn ) ;
299
- }
300
-
301
- _updatedClusterView ( ) {
302
- if ( ! this . _clusterView . needsUpdate ( ) ) {
303
- return Promise . resolve ( this . _clusterView ) ;
304
- } else {
305
- let routers = this . _clusterView . routers ;
306
- let acc = Promise . reject ( ) ;
307
- for ( let i = 0 ; i < routers . size ( ) ; i ++ ) {
308
- acc = acc . catch ( ( ) => {
309
- let conn = this . _pool . acquire ( routers . hop ( ) ) ;
310
- let session = this . _createSession ( Promise . resolve ( conn ) ) ;
311
- return newClusterView ( session ) . catch ( ( err ) => {
312
- this . _forget ( conn ) ;
313
- return Promise . reject ( err ) ;
314
- } ) ;
315
- } ) ;
316
- }
317
-
318
- return acc ;
319
- }
320
- }
321
- _diff ( oldView , updatedView ) {
322
- let oldSet = oldView . all ( ) ;
323
- let newSet = updatedView . all ( ) ;
324
- newSet . forEach ( ( item ) => {
325
- oldSet . delete ( item ) ;
326
- } ) ;
327
- return oldSet ;
328
- }
329
-
330
- _acquireConnection ( mode ) {
331
- let m = mode || WRITE ;
332
- //make sure we have enough servers
333
- return this . _updatedClusterView ( ) . then ( ( view ) => {
334
- let toRemove = this . _diff ( this . _clusterView , view ) ;
335
- let self = this ;
336
- toRemove . forEach ( ( url ) => {
337
- self . _pool . purge ( url ) ;
338
- } ) ;
339
- //update our cached view
340
- this . _clusterView = view ;
341
- if ( m === READ ) {
342
- return this . _pool . acquire ( view . readers . hop ( ) ) ;
343
- } else if ( m === WRITE ) {
344
- return this . _pool . acquire ( view . writers . hop ( ) ) ;
345
- } else {
346
- return Promise . reject ( m + " is not a valid option" ) ;
347
- }
348
- } ) ;
349
- }
350
-
351
- _forget ( url ) {
352
- this . _pool . purge ( url ) ;
353
- this . _clusterView . remove ( url ) ;
354
- }
355
- }
356
-
357
159
/** Internal stream observer used for connection state */
358
160
class _ConnectionStreamObserver extends StreamObserver {
359
161
constructor ( driver ) {
@@ -379,76 +181,8 @@ class _ConnectionStreamObserver extends StreamObserver {
379
181
}
380
182
}
381
183
382
- let USER_AGENT = "neo4j-javascript/" + VERSION ;
383
184
384
- /**
385
- * Construct a new Neo4j Driver. This is your main entry point for this
386
- * library.
387
- *
388
- * ## Configuration
389
- *
390
- * This function optionally takes a configuration argument. Available configuration
391
- * options are as follows:
392
- *
393
- * {
394
- * // Encryption level: one of ENCRYPTION_ON, ENCRYPTION_OFF or ENCRYPTION_NON_LOCAL.
395
- * // ENCRYPTION_NON_LOCAL is on by default in modern NodeJS installs,
396
- * // but off by default in the Web Bundle and old (<=1.0.0) NodeJS installs
397
- * // due to technical limitations on those platforms.
398
- * encrypted: ENCRYPTION_ON|ENCRYPTION_OFF|ENCRYPTION_NON_LOCAL
399
- *
400
- * // Trust strategy to use if encryption is enabled. There is no mode to disable
401
- * // trust other than disabling encryption altogether. The reason for
402
- * // this is that if you don't know who you are talking to, it is easy for an
403
- * // attacker to hijack your encrypted connection, rendering encryption pointless.
404
- * //
405
- * // TRUST_ON_FIRST_USE is the default for modern NodeJS deployments, and works
406
- * // similarly to how `ssl` works - the first time we connect to a new host,
407
- * // we remember the certificate they use. If the certificate ever changes, we
408
- * // assume it is an attempt to hijack the connection and require manual intervention.
409
- * // This means that by default, connections "just work" while still giving you
410
- * // good encrypted protection.
411
- * //
412
- * // TRUST_CUSTOM_CA_SIGNED_CERTIFICATES is the classic approach to trust verification -
413
- * // whenever we establish an encrypted connection, we ensure the host is using
414
- * // an encryption certificate that is in, or is signed by, a certificate listed
415
- * // as trusted. In the web bundle, this list of trusted certificates is maintained
416
- * // by the web browser. In NodeJS, you configure the list with the next config option.
417
- * //
418
- * // TRUST_SYSTEM_CA_SIGNED_CERTIFICATES meand that you trust whatever certificates
419
- * // are in the default certificate chain of th
420
- * trust: "TRUST_ON_FIRST_USE" | "TRUST_SIGNED_CERTIFICATES" | TRUST_CUSTOM_CA_SIGNED_CERTIFICATES |
421
- * TRUST_SYSTEM_CA_SIGNED_CERTIFICATES,
422
- *
423
- * // List of one or more paths to trusted encryption certificates. This only
424
- * // works in the NodeJS bundle, and only matters if you use "TRUST_CUSTOM_CA_SIGNED_CERTIFICATES".
425
- * // The certificate files should be in regular X.509 PEM format.
426
- * // For instance, ['./trusted.pem']
427
- * trustedCertificates: [],
428
- *
429
- * // Path to a file where the driver saves hosts it has seen in the past, this is
430
- * // very similar to the ssl tool's known_hosts file. Each time we connect to a
431
- * // new host, a hash of their certificate is stored along with the domain name and
432
- * // port, and this is then used to verify the host certificate does not change.
433
- * // This setting has no effect unless TRUST_ON_FIRST_USE is enabled.
434
- * knownHosts:"~/.neo4j/known_hosts",
435
- * }
436
- *
437
- * @param {string } url The URL for the Neo4j database, for instance "bolt://localhost"
438
- * @param {Map<String,String> } authToken Authentication credentials. See {@link auth} for helpers.
439
- * @param {Object } config Configuration object. See the configuration section above for details.
440
- * @returns {Driver }
441
- */
442
- function driver ( url , authToken , config = { } ) {
443
- let scheme = parseScheme ( url ) ;
444
- if ( scheme === "bolt+routing://" ) {
445
- return new RoutingDriver ( parseUrl ( url ) , USER_AGENT , authToken , config ) ;
446
- } else if ( scheme === "bolt://" ) {
447
- return new Driver ( parseUrl ( url ) , USER_AGENT , authToken , config ) ;
448
- } else {
449
- throw new Error ( "Unknown scheme: " + scheme ) ;
450
185
451
- }
452
- }
186
+ export { Driver , READ , WRITE }
453
187
454
- export { Driver , driver , READ , WRITE }
188
+ export default Driver
0 commit comments