2020import Session from './session' ;
2121import Pool from './internal/pool' ;
2222import Integer from './integer' ;
23- import { connect , parseScheme , parseUrl } from "./internal/connector" ;
23+ import { connect } from "./internal/connector" ;
2424import StreamObserver from './internal/stream-observer' ;
25- import VERSION from '../version' ;
26- import { newError , SERVICE_UNAVAILABLE , SESSION_EXPIRED } from "./error" ;
25+ import { newError } from "./error" ;
2726import "babel-polyfill" ;
2827
2928let READ = 'READ' , WRITE = 'WRITE' ;
@@ -157,203 +156,6 @@ class Driver {
157156 }
158157}
159158
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-
357159/** Internal stream observer used for connection state */
358160class _ConnectionStreamObserver extends StreamObserver {
359161 constructor ( driver ) {
@@ -379,76 +181,8 @@ class _ConnectionStreamObserver extends StreamObserver {
379181 }
380182}
381183
382- let USER_AGENT = "neo4j-javascript/" + VERSION ;
383184
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 ) ;
450185
451- }
452- }
186+ export { Driver , READ , WRITE }
453187
454- export { Driver , driver , READ , WRITE }
188+ export default Driver
0 commit comments