locker-factory
Version:
Content Locker UI Builder
256 lines (230 loc) • 7.86 kB
JavaScript
var Request = require( 'superagent' ),
Constants = require( './constants/Constants.js' ),
Config = require( './Config.js' ),
Dispatcher = require( './Dispatcher' ),
Emitter = require( 'events' ).EventEmitter,
Assign = require( 'object-assign' ),
TARGETING_URL = Config.proxyHostName + '/getoffers.php',
PROXY_URL = Config.proxyHostName + '/proxy.php',
LOCKER_TYPE = 'locker',
TIMEOUT = Config.timeout,
_pendingRequests = {};
/*
* Abort, null, and delete a pendingRequest for the specified key.
* Then check the pending requests to see if they are all fulfilled.
* @params key - The request key. Defined in constants.
* @returns undefined
*/
function abortPendingRequests( key ) {
if( _pendingRequests[ key ] ) {
_pendingRequests[ key ]._callback = function() {};
_pendingRequests[ key ].abort();
_pendingRequests[ key ] = null;
delete _pendingRequests[ key ];
}
checkPendingRequests( Constants.request.FULFILLED );
}
/*
* Check to see if we're opening an initial request.
* Add a pending request for the specificed key.
* @params key - The request key.
* @params request - The request itself.
* @returns undefined
*/
function addPendingRequest( key, request ) {
checkPendingRequests( Constants.request.OPENED );
_pendingRequests[ key ] = request;
}
/*
* Remove a pending request because the request is complete.
* Then check to see if all the requests are fulfilled.
* @params key - The request key.
* @returns undefined
*/
function removePendingRequest( key ) {
_pendingRequests[ key ] = null;
delete _pendingRequests[ key ];
checkPendingRequests( Constants.request.FULFILLED );
}
/*
* Check to see if there are no pending requests. If there are none,
* dispatch an event with the provided action key.
* This is used to dispatch events telling the UI that new requests have been opened
* or all open requests have been fulfilled so we can show or hide an ajax spinner.
* @param key - The action key.
* @returns undefined
*/
function checkPendingRequests( key ) {
if( Object.keys( _pendingRequests ).length == 0 ) {
Dispatcher.dispatch( { action: key } );
}
}
/*
* Dispatch an event from the api. This could be a new request or a response.
* Responses could be successful, timeout, or error. The action key, response type, response,
* and queryParams are passed in the payload.
* @param key - The action key.
* @param responseType - The response type (PENDING, TIMEOUT, ERROR, SUCCESS )
* @param params - Query parameters for the request.
* @param response - The response from the api. This is left out when requests are made initially.
* @returns undefined
*/
function dispatch( key, responseType, params, response ) {
var payload = {
action: key,
responseType: responseType,
response: response
};
if( params ) {
payload.queryParams = params;
}
Dispatcher.dispatch( payload );
}
/*
* Returns a function to be used as a callback when a response is received from the api server.
* This method will call the dispatch method and pass the appropraite response type and response.
* @param key - The action key.
* @param params - Query parameters from teh request.
* @param successCallback - A funciton to call with the successful response.
* @returns undefined
*/
function makeDigestFun( key, params, successCallback ) {
return function( err, resp ) {
if( err && err.timeout == TIMEOUT ) {
resp = {};
resp.statusText = err.message;
dispatch( key, Constants.request.TIMEOUT, params, resp );
} else if ( err || !resp.ok ) {
var payload = ( resp ? resp : err );
dispatch( key, Constants.request.ERROR, params, payload );
} else {
if( successCallback ) {
successCallback( resp );
}
dispatch( key, Constants.request.SUCCESS, params, resp );
}
removePendingRequest( key );
};
}
/*
* Create a GET request to our api proxy. Accept and Content-Type headers are set. Timeout is set.
* The query method is called passing the query parameters for our proxy to use to make the real request.
* @param params - The query params for the proxy.
* @returns undefined
*/
function get( params ) {
return Request.get( PROXY_URL )
.set( {
'Accept': 'application/json',
'Content-Type': 'application/json'
} )
.timeout( TIMEOUT )
.query( params );
}
/*
* Create a GET request to the getoffers.php endpoint. The params passed will include the api url,
* the locker key, the user ip, and the useragent.
* @param params - The parameters described above.
* @returns undefined
*/
function getOffers( params ) {
return Request.get( TARGETING_URL )
.set( {
'Accept': 'application/json',
'Content-Type': 'application/json'
} )
.timeout( TIMEOUT )
.query( params );
}
/*
* The Api object is an instance of the event emitter to allow us to emit request.OPENED and request.FULFILLED
* events to the UI. This probably isn't best practice, but it doesn't effect the state of the data and it works,
* so it's happening.
*/
var Api = Assign( {}, Emitter.prototype, {
/*
* Notify the UI that a new request has been opened.
* This should only happen when no other requests are pending.
*/
emitRequestOpened: function() {
this.emit( Constants.request.OPENED );
},
/*
* Add a listener for new request opened.
*/
addRequestOpenedListener: function( callback ) {
this.on( Constants.request.OPENED, callback );
},
/*
* Remove a listener for new request opened.
*/
removeRequestOpenedListener: function( callback ) {
this.removeListener( Constants.request.OPENED, callback );
},
/*
* Notify the UI that all requests have been fulfilled.
*/
emitRequestFulfilled: function() {
this.emit( Constants.request.FULFILLED );
},
/*
* Add a request fulfilled listener.
*/
addRequestFulfilledListener: function( callback ) {
this.on( Constants.request.FULFILLED, callback );
},
/*
* Remove a request fulfilled listener.
*/
removeRequestFulfilledListener: function( callback ) {
this.removeListener( Constants.request.FULFILLED, callback );
},
/*
* Make an api request to retrieve the campaigns that would
* appear in the end user locker UI.
* @param params - a key/value object of the query params for the request.
* @returns undefined
*/
getCampaigns: function( params ) {
var key = Constants.actions.GET_CAMPAIGNS;
params.url_type = LOCKER_TYPE;
params.url_key = 'campaigns';
abortPendingRequests( key );
dispatch( key, Constants.request.PENDING, params );
addPendingRequest( key, get( params ).end(
makeDigestFun( key, params )
) );
},
/*
* Make a request to the targeting endpoint. This endpoint
* accepts the locker key determines some targeting parameters.
*
* @param params - an object with the locker key
* @returns undefined
*/
getTargetedCampaigns: function( params ) {
var key = Constants.actions.GET_CAMPAIGNS;
abortPendingRequests( key );
dispatch( key, Constants.request.PENDING, params );
addPendingRequest( key, getOffers( params ).end(
makeDigestFun( key, params )
) );
}
} );
/*
* Register our request opened and fulfilled action processor that digests
* the dispatched action from checkPendingRequests.
*/
Dispatcher.register( function( action ) {
switch( action.action ) {
case Constants.request.OPENED:
Api.emitRequestOpened();
break;
case Constants.request.FULFILLED:
Api.emitRequestFulfilled();
break;
default:
// do nothing
}
} );
module.exports = Api;