[BC BREAK] DataApi config lookup
This was a bit involved because the system had to be made async all the way up the stack. No attempt was made to clean up the mess up the stack---no time. * src/dapi/DataApiFactory.js (fromType): [BC BREAK] Fix docblock. Add `api_name' param. Call `#descLookup' and return promise. (descLookup): Add method. Return promise resolving to provided descriptor. Intended to be overridden by subtype. * src/dapi/DataApiManager.js (_dataApis): Update docblock to indicate that it now stores promises. (getApiData): Expect promise for `DataApiFactory#fromType' call. * src/server/DocumentServer.js: (create): [BC BREAK] Accept configuration. Look up dapi conf and pass to `ServerDataApiFactory' ctor. Return promise. * src/server/daemon/Daemon.js (_initRouters): Provide configuration. * src/server/daemon/controller.js (init): Accept configuration. Handle return of promise from `_createDocumentServer'. (_createDocumentServer): Accept configuration, providing to `DocumentServer#create'. Because of aforementioned change to `#create', returns promise. * src/server/request/ServerDataApiFactory.js: Add StoreMissError import. (_conf): Add property. (constructor): [BC BREAK] Accept configuration. (descLookup): Add override. Look up configuration for provided dapi.master
parent
5f8fb2fcc5
commit
445783c256
|
@ -43,23 +43,44 @@ module.exports = Class( 'DataApiFactory',
|
||||||
* The source and method have type-specific meaning; that is, "source"
|
* The source and method have type-specific meaning; that is, "source"
|
||||||
* may be a URL and "method" may be get/post for a RESTful service.
|
* may be a URL and "method" may be get/post for a RESTful service.
|
||||||
*
|
*
|
||||||
* @param {string} type service type (e.g. "rest")
|
* @param {string} type service type (e.g. "rest")
|
||||||
* @param {Object} desc API description
|
* @param {Object} desc API description
|
||||||
|
* @param {Bucket} bucket active bucket
|
||||||
|
* @param {string} api_name dapi name
|
||||||
*
|
*
|
||||||
* @return {DataApi} appropriate DataApi instance
|
* @return {DataApi} appropriate DataApi instance
|
||||||
*/
|
*/
|
||||||
'public fromType': function( type, desc, bucket )
|
'public fromType': function( type, desc, bucket, api_name )
|
||||||
{
|
{
|
||||||
const static_data = ( desc['static'] || [] );
|
return this.descLookup( api_name, desc ).then( descl =>
|
||||||
const nonempty = !!desc.static_nonempty;
|
{
|
||||||
const multiple = !!desc.static_multiple;
|
const static_data = ( descl['static'] || [] );
|
||||||
|
const nonempty = !!descl.static_nonempty;
|
||||||
|
const multiple = !!descl.static_multiple;
|
||||||
|
|
||||||
const api = this._createDataApi( type, desc, bucket );
|
const api = this._createDataApi( type, descl, bucket );
|
||||||
|
|
||||||
return RestrictedDataApi(
|
return RestrictedDataApi(
|
||||||
StaticAdditionDataApi( api, nonempty, multiple, static_data ),
|
StaticAdditionDataApi( api, nonempty, multiple, static_data ),
|
||||||
desc
|
descl
|
||||||
);
|
);
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up dapi descriptor from configuration
|
||||||
|
*
|
||||||
|
* The default implementation just echoes back the given descriptor.
|
||||||
|
*
|
||||||
|
* @param {string} api_name dapi identifier
|
||||||
|
* @param {Object} desc given descriptor
|
||||||
|
*
|
||||||
|
* @return {Object} looked up descriptor
|
||||||
|
*/
|
||||||
|
'virtual protected descLookup'( api_name, desc )
|
||||||
|
{
|
||||||
|
return Promise.resolve( desc );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ module.exports = Class( 'DataApiManager' )
|
||||||
'private _dataApiFactory': null,
|
'private _dataApiFactory': null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DataApi instances, indexed by API id
|
* DataApi instance promises, indexed by API id
|
||||||
* @type {Object}
|
* @type {Object}
|
||||||
*/
|
*/
|
||||||
'private _dataApis': {},
|
'private _dataApis': {},
|
||||||
|
@ -157,18 +157,18 @@ module.exports = Class( 'DataApiManager' )
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the API if necessary (lazy-load); otherwise, use the existing
|
// create the API if necessary (lazy-load); otherwise, use the existing
|
||||||
// instance
|
// instance (well, a promise for one)
|
||||||
var api = this._dataApis[ api ] || ( function()
|
var apip = this._dataApis[ api ] || ( function()
|
||||||
{
|
{
|
||||||
var apidesc = _self._apis[ api ];
|
var apidesc = _self._apis[ api ];
|
||||||
|
|
||||||
// create a new instance of the API
|
// create a new instance of the API
|
||||||
return _self._dataApis[ api ] = _self._dataApiFactory.fromType(
|
return _self._dataApis[ api ] = _self._dataApiFactory.fromType(
|
||||||
apidesc.type, apidesc, bucket
|
apidesc.type, apidesc, bucket, api
|
||||||
).on( 'error', function( e )
|
)
|
||||||
{
|
.then( api =>
|
||||||
_self.emit( 'error', e );
|
api.on( 'error', e => _self.emit( 'error', e ) )
|
||||||
} );
|
);
|
||||||
} )();
|
} )();
|
||||||
|
|
||||||
// this has the effect of wiping out previous requests of the same id,
|
// this has the effect of wiping out previous requests of the same id,
|
||||||
|
@ -187,28 +187,22 @@ module.exports = Class( 'DataApiManager' )
|
||||||
};
|
};
|
||||||
|
|
||||||
// process the request; we'll let them know when it comes back
|
// process the request; we'll let them know when it comes back
|
||||||
try
|
apip.then( api => api.request( data, function()
|
||||||
{
|
{
|
||||||
api.request( data, function()
|
// we only wish to populate the field if the request should
|
||||||
|
// still be considered pending
|
||||||
|
var curuid = ( _self._pendingApiCall[ id ] || {} ).uid;
|
||||||
|
if ( curuid === uid )
|
||||||
{
|
{
|
||||||
// we only wish to populate the field if the request should
|
// forward to the caller
|
||||||
// still be considered pending
|
callback.apply( this, arguments );
|
||||||
var curuid = ( _self._pendingApiCall[ id ] || {} ).uid;
|
|
||||||
if ( curuid === uid )
|
|
||||||
{
|
|
||||||
// forward to the caller
|
|
||||||
callback.apply( this, arguments );
|
|
||||||
|
|
||||||
// clear the pending flag
|
// clear the pending flag
|
||||||
_self._pendingApiCall[ id ] = undefined;
|
_self._pendingApiCall[ id ] = undefined;
|
||||||
_self.emit( 'fieldLoaded', name, +index );
|
_self.emit( 'fieldLoaded', name, +index );
|
||||||
}
|
}
|
||||||
} );
|
} ) )
|
||||||
}
|
.catch( e => fc( e ) );
|
||||||
catch ( e )
|
|
||||||
{
|
|
||||||
fc( e );
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// field is about to be re-loaded
|
// field is about to be re-loaded
|
||||||
|
|
|
@ -53,23 +53,27 @@ const {
|
||||||
*/
|
*/
|
||||||
module.exports = Class( 'DocumentServer',
|
module.exports = Class( 'DocumentServer',
|
||||||
{
|
{
|
||||||
'public create': ( dao, logger, enc_service, origin_url ) => Server(
|
'public create': ( dao, logger, enc_service, origin_url, conf ) =>
|
||||||
new JsonServerResponse.create(),
|
Promise.all( [
|
||||||
dao,
|
conf.get( 'dapi' ),
|
||||||
logger,
|
] ).then( ([ dapi_conf ]) => Server(
|
||||||
enc_service,
|
new JsonServerResponse.create(),
|
||||||
|
dao,
|
||||||
|
logger,
|
||||||
|
enc_service,
|
||||||
|
|
||||||
DataProcessor(
|
DataProcessor(
|
||||||
bucket_filter,
|
bucket_filter,
|
||||||
( apis, request ) => DataApiManager(
|
( apis, request ) => DataApiManager(
|
||||||
ServerDataApiFactory(
|
ServerDataApiFactory(
|
||||||
origin_url || request.getOrigin(),
|
origin_url || request.getOrigin(),
|
||||||
request
|
request,
|
||||||
|
dapi_conf
|
||||||
|
),
|
||||||
|
apis
|
||||||
),
|
),
|
||||||
apis
|
DapiMetaSource( QuoteDataBucket ),
|
||||||
),
|
StagingBucket
|
||||||
DapiMetaSource( QuoteDataBucket ),
|
)
|
||||||
StagingBucket
|
) )
|
||||||
)
|
|
||||||
),
|
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -491,7 +491,7 @@ module.exports = AbstractClass( 'Daemon',
|
||||||
{
|
{
|
||||||
if ( router.init instanceof Function )
|
if ( router.init instanceof Function )
|
||||||
{
|
{
|
||||||
router.init( _self._debugLog, _self._encService );
|
router.init( _self._debugLog, _self._encService, _self._conf );
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -96,7 +96,7 @@ var sflag = {};
|
||||||
exports.rater = {};
|
exports.rater = {};
|
||||||
|
|
||||||
|
|
||||||
exports.init = function( logger, enc_service )
|
exports.init = function( logger, enc_service, conf )
|
||||||
{
|
{
|
||||||
var db = new MongoDb(
|
var db = new MongoDb(
|
||||||
'program',
|
'program',
|
||||||
|
@ -109,46 +109,50 @@ exports.init = function( logger, enc_service )
|
||||||
);
|
);
|
||||||
|
|
||||||
const dao = MongoServerDao( db );
|
const dao = MongoServerDao( db );
|
||||||
server = _createDocumentServer( dao, logger, enc_service );
|
|
||||||
|
|
||||||
server_cache = _createCache( server );
|
_createDocumentServer( dao, logger, enc_service, conf ).then( srv =>
|
||||||
server.init( server_cache, exports.rater );
|
|
||||||
|
|
||||||
rating_service = RatingService( logger, dao, server, exports.rater );
|
|
||||||
|
|
||||||
// TODO: exports.init needs to support callbacks; this will work, but
|
|
||||||
// only because it's unlikely that we'll get a request within
|
|
||||||
// milliseconds of coming online
|
|
||||||
_initExportService( db, function( service )
|
|
||||||
{
|
{
|
||||||
c1_export_service = service;
|
server = srv;
|
||||||
} );
|
|
||||||
|
|
||||||
server.on( 'quotePverUpdate', function( quote, program, event )
|
server_cache = _createCache( server );
|
||||||
{
|
server.init( server_cache, exports.rater );
|
||||||
// let them know that we're going to be a moment
|
|
||||||
var c = event.wait();
|
|
||||||
|
|
||||||
getCleaner( program ).clean( quote, function( err )
|
rating_service = RatingService( logger, dao, server, exports.rater );
|
||||||
|
|
||||||
|
// TODO: exports.init needs to support callbacks; this will work, but
|
||||||
|
// only because it's unlikely that we'll get a request within
|
||||||
|
// milliseconds of coming online
|
||||||
|
_initExportService( db, function( service )
|
||||||
{
|
{
|
||||||
// report on our success/failure
|
c1_export_service = service;
|
||||||
if ( err )
|
} );
|
||||||
{
|
|
||||||
event.bad( err );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
event.good();
|
|
||||||
}
|
|
||||||
|
|
||||||
// we're done
|
server.on( 'quotePverUpdate', function( quote, program, event )
|
||||||
c();
|
{
|
||||||
|
// let them know that we're going to be a moment
|
||||||
|
var c = event.wait();
|
||||||
|
|
||||||
|
getCleaner( program ).clean( quote, function( err )
|
||||||
|
{
|
||||||
|
// report on our success/failure
|
||||||
|
if ( err )
|
||||||
|
{
|
||||||
|
event.bad( err );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event.good();
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're done
|
||||||
|
c();
|
||||||
|
} );
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function _createDocumentServer( dao, logger, enc_service )
|
function _createDocumentServer( dao, logger, enc_service, conf )
|
||||||
{
|
{
|
||||||
const origin_url = process.env.HTTP_ORIGIN_URL || '';
|
const origin_url = process.env.HTTP_ORIGIN_URL || '';
|
||||||
|
|
||||||
|
@ -163,7 +167,8 @@ function _createDocumentServer( dao, logger, enc_service )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return DocumentServer().create( dao, logger, enc_service, origin_url );
|
return DocumentServer()
|
||||||
|
.create( dao, logger, enc_service, origin_url, conf );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,17 @@
|
||||||
|
|
||||||
const { Class } = require( 'easejs' );
|
const { Class } = require( 'easejs' );
|
||||||
const {
|
const {
|
||||||
DataApiFactory,
|
dapi: {
|
||||||
http: {
|
DataApiFactory,
|
||||||
NodeHttpImpl,
|
http: {
|
||||||
SpoofedNodeHttpImpl,
|
NodeHttpImpl,
|
||||||
|
SpoofedNodeHttpImpl,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} = require( '../..' ).dapi;
|
store: {
|
||||||
|
StoreMissError,
|
||||||
|
},
|
||||||
|
} = require( '../..' );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,11 +52,50 @@ module.exports = Class( 'ServerDataApiFactory' )
|
||||||
*/
|
*/
|
||||||
'private _session': null,
|
'private _session': null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dapi configuration
|
||||||
|
* @type {Store}
|
||||||
|
*/
|
||||||
|
'private _conf': null,
|
||||||
|
|
||||||
constructor( origin, session )
|
|
||||||
|
constructor( origin, session, conf )
|
||||||
{
|
{
|
||||||
this._origin = ''+origin;
|
this._origin = ''+origin;
|
||||||
this._session = session;
|
this._session = session;
|
||||||
|
this._conf = conf;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up dapi descriptor from configuration
|
||||||
|
*
|
||||||
|
* If no configuration is found for `api_name`, the original `desc` will
|
||||||
|
* be returned. Otherwise, they will be merged, with the lookup taking
|
||||||
|
* precedence.
|
||||||
|
*
|
||||||
|
* @param {string} api_name dapi identifier
|
||||||
|
* @param {Object} desc given descriptor
|
||||||
|
*
|
||||||
|
* @return {Object} looked up descriptor
|
||||||
|
*/
|
||||||
|
'override protected descLookup'( api_name, desc )
|
||||||
|
{
|
||||||
|
return this._conf.get( 'aliases' )
|
||||||
|
.then( aliases => aliases.get( api_name ) )
|
||||||
|
.then( desc_lookup => desc_lookup.reduce(
|
||||||
|
( ret, value, key ) =>
|
||||||
|
{
|
||||||
|
// merges the two, with lookup taking precedence
|
||||||
|
ret[ key ] = value;
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
Object.create( desc )
|
||||||
|
) )
|
||||||
|
.catch( e => ( Class.isA( StoreMissError, e ) )
|
||||||
|
? desc
|
||||||
|
: Promise.reject( e )
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ function createStubDapiFactory( dapis )
|
||||||
return {
|
return {
|
||||||
fromType( type )
|
fromType( type )
|
||||||
{
|
{
|
||||||
return dapis[ type ];
|
return Promise.resolve( dapis[ type ] );
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue