UNPKG

locker-factory

Version:
256 lines (230 loc) 7.86 kB
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;