1616 * See the License for the specific language governing permissions and
1717 * limitations under the License.
1818 */
19+
1920import WebSocketChannel from './ch-websocket' ;
2021import NodeChannel from './ch-node' ;
2122import { Chunker , Dechunker } from './chunking' ;
@@ -24,6 +25,8 @@ import {alloc} from './buf';
2425import { Node , Path , PathSegment , Relationship , UnboundRelationship } from '../graph-types' ;
2526import { newError } from './../error' ;
2627import ChannelConfig from './ch-config' ;
28+ import { parseHost , parsePort } from './util' ;
29+ import StreamObserver from './stream-observer' ;
2730
2831let Channel ;
2932if ( NodeChannel . available ) {
@@ -59,29 +62,6 @@ PATH = 0x50,
5962MAGIC_PREAMBLE = 0x6060B017 ,
6063DEBUG = false ;
6164
62- let URLREGEX = new RegExp ( [
63- "([^/]+//)?" , // scheme
64- "(([^:/?#]*)" , // hostname
65- "(?::([0-9]+))?)" , // port (optional)
66- ".*" ] . join ( "" ) ) ; // everything else
67-
68- function parseScheme ( url ) {
69- let scheme = url . match ( URLREGEX ) [ 1 ] || '' ;
70- return scheme . toLowerCase ( ) ;
71- }
72-
73- function parseUrl ( url ) {
74- return url . match ( URLREGEX ) [ 2 ] ;
75- }
76-
77- function parseHost ( url ) {
78- return url . match ( URLREGEX ) [ 3 ] ;
79- }
80-
81- function parsePort ( url ) {
82- return url . match ( URLREGEX ) [ 4 ] ;
83- }
84-
8565/**
8666 * Very rudimentary log handling, should probably be replaced by something proper at some point.
8767 * @param actor the part that sent the message, 'S' for server and 'C' for client
@@ -204,6 +184,8 @@ class Connection {
204184 this . _isHandlingFailure = false ;
205185 this . _currentFailure = null ;
206186
187+ this . _state = new ConnectionState ( this ) ;
188+
207189 // Set to true on fatal errors, to get this out of session pool.
208190 this . _isBroken = false ;
209191
@@ -351,7 +333,8 @@ class Connection {
351333 /** Queue an INIT-message to be sent to the database */
352334 initialize ( clientName , token , observer ) {
353335 log ( "C" , "INIT" , clientName , token ) ;
354- this . _queueObserver ( observer ) ;
336+ const initObserver = this . _state . wrap ( observer ) ;
337+ this . _queueObserver ( initObserver ) ;
355338 this . _packer . packStruct ( INIT , [ this . _packable ( clientName ) , this . _packable ( token ) ] ,
356339 ( err ) => this . _handleFatalError ( err ) ) ;
357340 this . _chunker . messageBoundary ( ) ;
@@ -437,6 +420,15 @@ class Connection {
437420 }
438421 }
439422
423+ /**
424+ * Get promise resolved when connection initialization succeed or rejected when it fails.
425+ * Connection is initialized using {@link initialize} function.
426+ * @return {Promise<Connection> } the result of connection initialization.
427+ */
428+ initializationCompleted ( ) {
429+ return this . _state . initializationCompleted ( ) ;
430+ }
431+
440432 /**
441433 * Synchronize - flush all queued outgoing messages and route their responses
442434 * to their respective handlers.
@@ -471,6 +463,78 @@ class Connection {
471463 }
472464}
473465
466+ class ConnectionState {
467+
468+ /**
469+ * @constructor
470+ * @param {Connection } connection the connection to track state for.
471+ */
472+ constructor ( connection ) {
473+ this . _connection = connection ;
474+
475+ this . _initialized = false ;
476+ this . _initializationError = null ;
477+
478+ this . _resolvePromise = null ;
479+ this . _rejectPromise = null ;
480+ }
481+
482+ /**
483+ * Wrap the given observer to track connection's initialization state.
484+ * @param {StreamObserver } observer the observer used for INIT message.
485+ * @return {StreamObserver } updated observer.
486+ */
487+ wrap ( observer ) {
488+ return {
489+ onNext : record => {
490+ if ( observer && observer . onNext ) {
491+ observer . onNext ( record ) ;
492+ }
493+ } ,
494+ onError : error => {
495+ this . _initializationError = error ;
496+ if ( this . _rejectPromise ) {
497+ this . _rejectPromise ( error ) ;
498+ this . _rejectPromise = null ;
499+ }
500+ if ( observer && observer . onError ) {
501+ observer . onError ( error ) ;
502+ }
503+ } ,
504+ onCompleted : metaData => {
505+ if ( metaData && metaData . server ) {
506+ this . _connection . setServerVersion ( metaData . server ) ;
507+ }
508+ this . _initialized = true ;
509+ if ( this . _resolvePromise ) {
510+ this . _resolvePromise ( this . _connection ) ;
511+ this . _resolvePromise = null ;
512+ }
513+ if ( observer && observer . onCompleted ) {
514+ observer . onCompleted ( metaData ) ;
515+ }
516+ }
517+ } ;
518+ }
519+
520+ /**
521+ * Get promise resolved when connection initialization succeed or rejected when it fails.
522+ * @return {Promise<Connection> } the result of connection initialization.
523+ */
524+ initializationCompleted ( ) {
525+ if ( this . _initialized ) {
526+ return Promise . resolve ( this . _connection ) ;
527+ } else if ( this . _initializationError ) {
528+ return Promise . reject ( this . _initializationError ) ;
529+ } else {
530+ return new Promise ( ( resolve , reject ) => {
531+ this . _resolvePromise = resolve ;
532+ this . _rejectPromise = reject ;
533+ } ) ;
534+ }
535+ }
536+ }
537+
474538/**
475539 * Crete new connection to the provided url.
476540 * @access private
@@ -490,10 +554,6 @@ function connect(url, config = {}, connectionErrorCode = null) {
490554}
491555
492556export {
493- connect ,
494- parseScheme ,
495- parseUrl ,
496- parseHost ,
497- parsePort ,
498- Connection
499- }
557+ connect ,
558+ Connection
559+ } ;
0 commit comments