Skip to content

Commit f3e3d01

Browse files
committed
Refactoring: moved classes and functions into separate files
1 parent 591f2a7 commit f3e3d01

File tree

6 files changed

+467
-273
lines changed

6 files changed

+467
-273
lines changed

src/v1/driver.js

+4-270
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@
2020
import Session from './session';
2121
import Pool from './internal/pool';
2222
import Integer from './integer';
23-
import {connect, parseScheme, parseUrl} from "./internal/connector";
23+
import {connect} from "./internal/connector";
2424
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";
2726
import "babel-polyfill";
2827

2928
let 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 */
358160
class _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

src/v1/index.js

+77-2
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@
1818
*/
1919

2020
import {int, isInt} from './integer';
21-
import {driver} from './driver';
2221
import {Node, Relationship, UnboundRelationship, PathSegment, Path} from './graph-types'
2322
import {Neo4jError, SERVICE_UNAVAILABLE, SESSION_EXPIRED} from './error';
2423
import Result from './result';
2524
import ResultSummary from './result-summary';
2625
import Record from './record';
27-
import {READ, WRITE} from './driver';
26+
import {Driver, READ, WRITE} from './driver';
27+
import RoutingDriver from './routing-driver';
28+
import VERSION from '../version';
29+
import {parseScheme, parseUrl} from "./internal/connector";
30+
2831

2932
const auth ={
3033
basic: (username, password, realm = undefined) => {
@@ -43,6 +46,78 @@ const auth ={
4346
}
4447
}
4548
};
49+
let USER_AGENT = "neo4j-javascript/" + VERSION;
50+
51+
/**
52+
* Construct a new Neo4j Driver. This is your main entry point for this
53+
* library.
54+
*
55+
* ## Configuration
56+
*
57+
* This function optionally takes a configuration argument. Available configuration
58+
* options are as follows:
59+
*
60+
* {
61+
* // Encryption level: one of ENCRYPTION_ON, ENCRYPTION_OFF or ENCRYPTION_NON_LOCAL.
62+
* // ENCRYPTION_NON_LOCAL is on by default in modern NodeJS installs,
63+
* // but off by default in the Web Bundle and old (<=1.0.0) NodeJS installs
64+
* // due to technical limitations on those platforms.
65+
* encrypted: ENCRYPTION_ON|ENCRYPTION_OFF|ENCRYPTION_NON_LOCAL
66+
*
67+
* // Trust strategy to use if encryption is enabled. There is no mode to disable
68+
* // trust other than disabling encryption altogether. The reason for
69+
* // this is that if you don't know who you are talking to, it is easy for an
70+
* // attacker to hijack your encrypted connection, rendering encryption pointless.
71+
* //
72+
* // TRUST_ON_FIRST_USE is the default for modern NodeJS deployments, and works
73+
* // similarly to how `ssl` works - the first time we connect to a new host,
74+
* // we remember the certificate they use. If the certificate ever changes, we
75+
* // assume it is an attempt to hijack the connection and require manual intervention.
76+
* // This means that by default, connections "just work" while still giving you
77+
* // good encrypted protection.
78+
* //
79+
* // TRUST_CUSTOM_CA_SIGNED_CERTIFICATES is the classic approach to trust verification -
80+
* // whenever we establish an encrypted connection, we ensure the host is using
81+
* // an encryption certificate that is in, or is signed by, a certificate listed
82+
* // as trusted. In the web bundle, this list of trusted certificates is maintained
83+
* // by the web browser. In NodeJS, you configure the list with the next config option.
84+
* //
85+
* // TRUST_SYSTEM_CA_SIGNED_CERTIFICATES meand that you trust whatever certificates
86+
* // are in the default certificate chain of th
87+
* trust: "TRUST_ON_FIRST_USE" | "TRUST_SIGNED_CERTIFICATES" | TRUST_CUSTOM_CA_SIGNED_CERTIFICATES |
88+
* TRUST_SYSTEM_CA_SIGNED_CERTIFICATES,
89+
*
90+
* // List of one or more paths to trusted encryption certificates. This only
91+
* // works in the NodeJS bundle, and only matters if you use "TRUST_CUSTOM_CA_SIGNED_CERTIFICATES".
92+
* // The certificate files should be in regular X.509 PEM format.
93+
* // For instance, ['./trusted.pem']
94+
* trustedCertificates: [],
95+
*
96+
* // Path to a file where the driver saves hosts it has seen in the past, this is
97+
* // very similar to the ssl tool's known_hosts file. Each time we connect to a
98+
* // new host, a hash of their certificate is stored along with the domain name and
99+
* // port, and this is then used to verify the host certificate does not change.
100+
* // This setting has no effect unless TRUST_ON_FIRST_USE is enabled.
101+
* knownHosts:"~/.neo4j/known_hosts",
102+
* }
103+
*
104+
* @param {string} url The URL for the Neo4j database, for instance "bolt://localhost"
105+
* @param {Map<String,String>} authToken Authentication credentials. See {@link auth} for helpers.
106+
* @param {Object} config Configuration object. See the configuration section above for details.
107+
* @returns {Driver}
108+
*/
109+
function driver(url, authToken, config = {}) {
110+
let scheme = parseScheme(url);
111+
if (scheme === "bolt+routing://") {
112+
return new RoutingDriver(parseUrl(url), USER_AGENT, authToken, config);
113+
} else if (scheme === "bolt://") {
114+
return new Driver(parseUrl(url), USER_AGENT, authToken, config);
115+
} else {
116+
throw new Error("Unknown scheme: " + scheme);
117+
118+
}
119+
}
120+
46121

47122
const types ={
48123
Node,

0 commit comments

Comments
 (0)