1
0
Fork 0

[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
Mike Gerwitz 2017-08-29 15:00:16 -04:00
parent 5f8fb2fcc5
commit 445783c256
7 changed files with 162 additions and 94 deletions

View File

@ -43,23 +43,44 @@ module.exports = Class( 'DataApiFactory',
* 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.
*
* @param {string} type service type (e.g. "rest")
* @param {Object} desc API description
* @param {string} type service type (e.g. "rest")
* @param {Object} desc API description
* @param {Bucket} bucket active bucket
* @param {string} api_name dapi name
*
* @return {DataApi} appropriate DataApi instance
*/
'public fromType': function( type, desc, bucket )
'public fromType': function( type, desc, bucket, api_name )
{
const static_data = ( desc['static'] || [] );
const nonempty = !!desc.static_nonempty;
const multiple = !!desc.static_multiple;
return this.descLookup( api_name, desc ).then( descl =>
{
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(
StaticAdditionDataApi( api, nonempty, multiple, static_data ),
desc
);
return RestrictedDataApi(
StaticAdditionDataApi( api, nonempty, multiple, static_data ),
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 );
},

View File

@ -38,7 +38,7 @@ module.exports = Class( 'DataApiManager' )
'private _dataApiFactory': null,
/**
* DataApi instances, indexed by API id
* DataApi instance promises, indexed by API id
* @type {Object}
*/
'private _dataApis': {},
@ -157,18 +157,18 @@ module.exports = Class( 'DataApiManager' )
}
// create the API if necessary (lazy-load); otherwise, use the existing
// instance
var api = this._dataApis[ api ] || ( function()
// instance (well, a promise for one)
var apip = this._dataApis[ api ] || ( function()
{
var apidesc = _self._apis[ api ];
// create a new instance of the API
return _self._dataApis[ api ] = _self._dataApiFactory.fromType(
apidesc.type, apidesc, bucket
).on( 'error', function( e )
{
_self.emit( 'error', e );
} );
apidesc.type, apidesc, bucket, api
)
.then( api =>
api.on( 'error', e => _self.emit( 'error', e ) )
);
} )();
// 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
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
// still be considered pending
var curuid = ( _self._pendingApiCall[ id ] || {} ).uid;
if ( curuid === uid )
{
// forward to the caller
callback.apply( this, arguments );
// forward to the caller
callback.apply( this, arguments );
// clear the pending flag
_self._pendingApiCall[ id ] = undefined;
_self.emit( 'fieldLoaded', name, +index );
}
} );
}
catch ( e )
{
fc( e );
}
// clear the pending flag
_self._pendingApiCall[ id ] = undefined;
_self.emit( 'fieldLoaded', name, +index );
}
} ) )
.catch( e => fc( e ) );
};
// field is about to be re-loaded

View File

@ -53,23 +53,27 @@ const {
*/
module.exports = Class( 'DocumentServer',
{
'public create': ( dao, logger, enc_service, origin_url ) => Server(
new JsonServerResponse.create(),
dao,
logger,
enc_service,
'public create': ( dao, logger, enc_service, origin_url, conf ) =>
Promise.all( [
conf.get( 'dapi' ),
] ).then( ([ dapi_conf ]) => Server(
new JsonServerResponse.create(),
dao,
logger,
enc_service,
DataProcessor(
bucket_filter,
( apis, request ) => DataApiManager(
ServerDataApiFactory(
origin_url || request.getOrigin(),
request
DataProcessor(
bucket_filter,
( apis, request ) => DataApiManager(
ServerDataApiFactory(
origin_url || request.getOrigin(),
request,
dapi_conf
),
apis
),
apis
),
DapiMetaSource( QuoteDataBucket ),
StagingBucket
)
),
DapiMetaSource( QuoteDataBucket ),
StagingBucket
)
) )
} );

View File

@ -491,7 +491,7 @@ module.exports = AbstractClass( 'Daemon',
{
if ( router.init instanceof Function )
{
router.init( _self._debugLog, _self._encService );
router.init( _self._debugLog, _self._encService, _self._conf );
}
});
},

View File

@ -96,7 +96,7 @@ var sflag = {};
exports.rater = {};
exports.init = function( logger, enc_service )
exports.init = function( logger, enc_service, conf )
{
var db = new MongoDb(
'program',
@ -109,46 +109,50 @@ exports.init = function( logger, enc_service )
);
const dao = MongoServerDao( db );
server = _createDocumentServer( dao, logger, enc_service );
server_cache = _createCache( server );
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 )
_createDocumentServer( dao, logger, enc_service, conf ).then( srv =>
{
c1_export_service = service;
} );
server = srv;
server.on( 'quotePverUpdate', function( quote, program, event )
{
// let them know that we're going to be a moment
var c = event.wait();
server_cache = _createCache( server );
server.init( server_cache, exports.rater );
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
if ( err )
{
event.bad( err );
}
else
{
event.good();
}
c1_export_service = service;
} );
// we're done
c();
server.on( 'quotePverUpdate', function( quote, program, event )
{
// 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 || '';
@ -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 );
}

View File

@ -21,12 +21,17 @@
const { Class } = require( 'easejs' );
const {
DataApiFactory,
http: {
NodeHttpImpl,
SpoofedNodeHttpImpl,
dapi: {
DataApiFactory,
http: {
NodeHttpImpl,
SpoofedNodeHttpImpl,
},
},
} = require( '../..' ).dapi;
store: {
StoreMissError,
},
} = require( '../..' );
/**
@ -47,11 +52,50 @@ module.exports = Class( 'ServerDataApiFactory' )
*/
'private _session': null,
/**
* Dapi configuration
* @type {Store}
*/
'private _conf': null,
constructor( origin, session )
constructor( origin, session, conf )
{
this._origin = ''+origin;
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 )
);
},

View File

@ -116,7 +116,7 @@ function createStubDapiFactory( dapis )
return {
fromType( type )
{
return dapis[ type ];
return Promise.resolve( dapis[ type ] );
},
};
}