123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854 |
- var AWS = require('./core');
- var Api = require('./model/api');
- var regionConfig = require('./region_config');
- var inherit = AWS.util.inherit;
- var clientCount = 0;
- var region_utils = require('./region/utils');
- /**
- * The service class representing an AWS service.
- *
- * @class_abstract This class is an abstract class.
- *
- * @!attribute apiVersions
- * @return [Array<String>] the list of API versions supported by this service.
- * @readonly
- */
- AWS.Service = inherit({
- /**
- * Create a new service object with a configuration object
- *
- * @param config [map] a map of configuration options
- */
- constructor: function Service(config) {
- if (!this.loadServiceClass) {
- throw AWS.util.error(new Error(),
- 'Service must be constructed with `new\' operator');
- }
- if (config) {
- if (config.region) {
- var region = config.region;
- if (region_utils.isFipsRegion(region)) {
- config.region = region_utils.getRealRegion(region);
- config.useFipsEndpoint = true;
- }
- if (region_utils.isGlobalRegion(region)) {
- config.region = region_utils.getRealRegion(region);
- }
- }
- if (typeof config.useDualstack === 'boolean'
- && typeof config.useDualstackEndpoint !== 'boolean') {
- config.useDualstackEndpoint = config.useDualstack;
- }
- }
- var ServiceClass = this.loadServiceClass(config || {});
- if (ServiceClass) {
- var originalConfig = AWS.util.copy(config);
- var svc = new ServiceClass(config);
- Object.defineProperty(svc, '_originalConfig', {
- get: function() { return originalConfig; },
- enumerable: false,
- configurable: true
- });
- svc._clientId = ++clientCount;
- return svc;
- }
- this.initialize(config);
- },
- /**
- * @api private
- */
- initialize: function initialize(config) {
- var svcConfig = AWS.config[this.serviceIdentifier];
- this.config = new AWS.Config(AWS.config);
- if (svcConfig) this.config.update(svcConfig, true);
- if (config) this.config.update(config, true);
- this.validateService();
- if (!this.config.endpoint) regionConfig.configureEndpoint(this);
- this.config.endpoint = this.endpointFromTemplate(this.config.endpoint);
- this.setEndpoint(this.config.endpoint);
- //enable attaching listeners to service client
- AWS.SequentialExecutor.call(this);
- AWS.Service.addDefaultMonitoringListeners(this);
- if ((this.config.clientSideMonitoring || AWS.Service._clientSideMonitoring) && this.publisher) {
- var publisher = this.publisher;
- this.addNamedListener('PUBLISH_API_CALL', 'apiCall', function PUBLISH_API_CALL(event) {
- process.nextTick(function() {publisher.eventHandler(event);});
- });
- this.addNamedListener('PUBLISH_API_ATTEMPT', 'apiCallAttempt', function PUBLISH_API_ATTEMPT(event) {
- process.nextTick(function() {publisher.eventHandler(event);});
- });
- }
- },
- /**
- * @api private
- */
- validateService: function validateService() {
- },
- /**
- * @api private
- */
- loadServiceClass: function loadServiceClass(serviceConfig) {
- var config = serviceConfig;
- if (!AWS.util.isEmpty(this.api)) {
- return null;
- } else if (config.apiConfig) {
- return AWS.Service.defineServiceApi(this.constructor, config.apiConfig);
- } else if (!this.constructor.services) {
- return null;
- } else {
- config = new AWS.Config(AWS.config);
- config.update(serviceConfig, true);
- var version = config.apiVersions[this.constructor.serviceIdentifier];
- version = version || config.apiVersion;
- return this.getLatestServiceClass(version);
- }
- },
- /**
- * @api private
- */
- getLatestServiceClass: function getLatestServiceClass(version) {
- version = this.getLatestServiceVersion(version);
- if (this.constructor.services[version] === null) {
- AWS.Service.defineServiceApi(this.constructor, version);
- }
- return this.constructor.services[version];
- },
- /**
- * @api private
- */
- getLatestServiceVersion: function getLatestServiceVersion(version) {
- if (!this.constructor.services || this.constructor.services.length === 0) {
- throw new Error('No services defined on ' +
- this.constructor.serviceIdentifier);
- }
- if (!version) {
- version = 'latest';
- } else if (AWS.util.isType(version, Date)) {
- version = AWS.util.date.iso8601(version).split('T')[0];
- }
- if (Object.hasOwnProperty(this.constructor.services, version)) {
- return version;
- }
- var keys = Object.keys(this.constructor.services).sort();
- var selectedVersion = null;
- for (var i = keys.length - 1; i >= 0; i--) {
- // versions that end in "*" are not available on disk and can be
- // skipped, so do not choose these as selectedVersions
- if (keys[i][keys[i].length - 1] !== '*') {
- selectedVersion = keys[i];
- }
- if (keys[i].substr(0, 10) <= version) {
- return selectedVersion;
- }
- }
- throw new Error('Could not find ' + this.constructor.serviceIdentifier +
- ' API to satisfy version constraint `' + version + '\'');
- },
- /**
- * @api private
- */
- api: {},
- /**
- * @api private
- */
- defaultRetryCount: 3,
- /**
- * @api private
- */
- customizeRequests: function customizeRequests(callback) {
- if (!callback) {
- this.customRequestHandler = null;
- } else if (typeof callback === 'function') {
- this.customRequestHandler = callback;
- } else {
- throw new Error('Invalid callback type \'' + typeof callback + '\' provided in customizeRequests');
- }
- },
- /**
- * Calls an operation on a service with the given input parameters.
- *
- * @param operation [String] the name of the operation to call on the service.
- * @param params [map] a map of input options for the operation
- * @callback callback function(err, data)
- * If a callback is supplied, it is called when a response is returned
- * from the service.
- * @param err [Error] the error object returned from the request.
- * Set to `null` if the request is successful.
- * @param data [Object] the de-serialized data returned from
- * the request. Set to `null` if a request error occurs.
- */
- makeRequest: function makeRequest(operation, params, callback) {
- if (typeof params === 'function') {
- callback = params;
- params = null;
- }
- params = params || {};
- if (this.config.params) { // copy only toplevel bound params
- var rules = this.api.operations[operation];
- if (rules) {
- params = AWS.util.copy(params);
- AWS.util.each(this.config.params, function(key, value) {
- if (rules.input.members[key]) {
- if (params[key] === undefined || params[key] === null) {
- params[key] = value;
- }
- }
- });
- }
- }
- var request = new AWS.Request(this, operation, params);
- this.addAllRequestListeners(request);
- this.attachMonitoringEmitter(request);
- if (callback) request.send(callback);
- return request;
- },
- /**
- * Calls an operation on a service with the given input parameters, without
- * any authentication data. This method is useful for "public" API operations.
- *
- * @param operation [String] the name of the operation to call on the service.
- * @param params [map] a map of input options for the operation
- * @callback callback function(err, data)
- * If a callback is supplied, it is called when a response is returned
- * from the service.
- * @param err [Error] the error object returned from the request.
- * Set to `null` if the request is successful.
- * @param data [Object] the de-serialized data returned from
- * the request. Set to `null` if a request error occurs.
- */
- makeUnauthenticatedRequest: function makeUnauthenticatedRequest(operation, params, callback) {
- if (typeof params === 'function') {
- callback = params;
- params = {};
- }
- var request = this.makeRequest(operation, params).toUnauthenticated();
- return callback ? request.send(callback) : request;
- },
- /**
- * Waits for a given state
- *
- * @param state [String] the state on the service to wait for
- * @param params [map] a map of parameters to pass with each request
- * @option params $waiter [map] a map of configuration options for the waiter
- * @option params $waiter.delay [Number] The number of seconds to wait between
- * requests
- * @option params $waiter.maxAttempts [Number] The maximum number of requests
- * to send while waiting
- * @callback callback function(err, data)
- * If a callback is supplied, it is called when a response is returned
- * from the service.
- * @param err [Error] the error object returned from the request.
- * Set to `null` if the request is successful.
- * @param data [Object] the de-serialized data returned from
- * the request. Set to `null` if a request error occurs.
- */
- waitFor: function waitFor(state, params, callback) {
- var waiter = new AWS.ResourceWaiter(this, state);
- return waiter.wait(params, callback);
- },
- /**
- * @api private
- */
- addAllRequestListeners: function addAllRequestListeners(request) {
- var list = [AWS.events, AWS.EventListeners.Core, this.serviceInterface(),
- AWS.EventListeners.CorePost];
- for (var i = 0; i < list.length; i++) {
- if (list[i]) request.addListeners(list[i]);
- }
- // disable parameter validation
- if (!this.config.paramValidation) {
- request.removeListener('validate',
- AWS.EventListeners.Core.VALIDATE_PARAMETERS);
- }
- if (this.config.logger) { // add logging events
- request.addListeners(AWS.EventListeners.Logger);
- }
- this.setupRequestListeners(request);
- // call prototype's customRequestHandler
- if (typeof this.constructor.prototype.customRequestHandler === 'function') {
- this.constructor.prototype.customRequestHandler(request);
- }
- // call instance's customRequestHandler
- if (Object.prototype.hasOwnProperty.call(this, 'customRequestHandler') && typeof this.customRequestHandler === 'function') {
- this.customRequestHandler(request);
- }
- },
- /**
- * Event recording metrics for a whole API call.
- * @returns {object} a subset of api call metrics
- * @api private
- */
- apiCallEvent: function apiCallEvent(request) {
- var api = request.service.api.operations[request.operation];
- var monitoringEvent = {
- Type: 'ApiCall',
- Api: api ? api.name : request.operation,
- Version: 1,
- Service: request.service.api.serviceId || request.service.api.endpointPrefix,
- Region: request.httpRequest.region,
- MaxRetriesExceeded: 0,
- UserAgent: request.httpRequest.getUserAgent(),
- };
- var response = request.response;
- if (response.httpResponse.statusCode) {
- monitoringEvent.FinalHttpStatusCode = response.httpResponse.statusCode;
- }
- if (response.error) {
- var error = response.error;
- var statusCode = response.httpResponse.statusCode;
- if (statusCode > 299) {
- if (error.code) monitoringEvent.FinalAwsException = error.code;
- if (error.message) monitoringEvent.FinalAwsExceptionMessage = error.message;
- } else {
- if (error.code || error.name) monitoringEvent.FinalSdkException = error.code || error.name;
- if (error.message) monitoringEvent.FinalSdkExceptionMessage = error.message;
- }
- }
- return monitoringEvent;
- },
- /**
- * Event recording metrics for an API call attempt.
- * @returns {object} a subset of api call attempt metrics
- * @api private
- */
- apiAttemptEvent: function apiAttemptEvent(request) {
- var api = request.service.api.operations[request.operation];
- var monitoringEvent = {
- Type: 'ApiCallAttempt',
- Api: api ? api.name : request.operation,
- Version: 1,
- Service: request.service.api.serviceId || request.service.api.endpointPrefix,
- Fqdn: request.httpRequest.endpoint.hostname,
- UserAgent: request.httpRequest.getUserAgent(),
- };
- var response = request.response;
- if (response.httpResponse.statusCode) {
- monitoringEvent.HttpStatusCode = response.httpResponse.statusCode;
- }
- if (
- !request._unAuthenticated &&
- request.service.config.credentials &&
- request.service.config.credentials.accessKeyId
- ) {
- monitoringEvent.AccessKey = request.service.config.credentials.accessKeyId;
- }
- if (!response.httpResponse.headers) return monitoringEvent;
- if (request.httpRequest.headers['x-amz-security-token']) {
- monitoringEvent.SessionToken = request.httpRequest.headers['x-amz-security-token'];
- }
- if (response.httpResponse.headers['x-amzn-requestid']) {
- monitoringEvent.XAmznRequestId = response.httpResponse.headers['x-amzn-requestid'];
- }
- if (response.httpResponse.headers['x-amz-request-id']) {
- monitoringEvent.XAmzRequestId = response.httpResponse.headers['x-amz-request-id'];
- }
- if (response.httpResponse.headers['x-amz-id-2']) {
- monitoringEvent.XAmzId2 = response.httpResponse.headers['x-amz-id-2'];
- }
- return monitoringEvent;
- },
- /**
- * Add metrics of failed request.
- * @api private
- */
- attemptFailEvent: function attemptFailEvent(request) {
- var monitoringEvent = this.apiAttemptEvent(request);
- var response = request.response;
- var error = response.error;
- if (response.httpResponse.statusCode > 299 ) {
- if (error.code) monitoringEvent.AwsException = error.code;
- if (error.message) monitoringEvent.AwsExceptionMessage = error.message;
- } else {
- if (error.code || error.name) monitoringEvent.SdkException = error.code || error.name;
- if (error.message) monitoringEvent.SdkExceptionMessage = error.message;
- }
- return monitoringEvent;
- },
- /**
- * Attach listeners to request object to fetch metrics of each request
- * and emit data object through \'ApiCall\' and \'ApiCallAttempt\' events.
- * @api private
- */
- attachMonitoringEmitter: function attachMonitoringEmitter(request) {
- var attemptTimestamp; //timestamp marking the beginning of a request attempt
- var attemptStartRealTime; //Start time of request attempt. Used to calculating attemptLatency
- var attemptLatency; //latency from request sent out to http response reaching SDK
- var callStartRealTime; //Start time of API call. Used to calculating API call latency
- var attemptCount = 0; //request.retryCount is not reliable here
- var region; //region cache region for each attempt since it can be updated in plase (e.g. s3)
- var callTimestamp; //timestamp when the request is created
- var self = this;
- var addToHead = true;
- request.on('validate', function () {
- callStartRealTime = AWS.util.realClock.now();
- callTimestamp = Date.now();
- }, addToHead);
- request.on('sign', function () {
- attemptStartRealTime = AWS.util.realClock.now();
- attemptTimestamp = Date.now();
- region = request.httpRequest.region;
- attemptCount++;
- }, addToHead);
- request.on('validateResponse', function() {
- attemptLatency = Math.round(AWS.util.realClock.now() - attemptStartRealTime);
- });
- request.addNamedListener('API_CALL_ATTEMPT', 'success', function API_CALL_ATTEMPT() {
- var apiAttemptEvent = self.apiAttemptEvent(request);
- apiAttemptEvent.Timestamp = attemptTimestamp;
- apiAttemptEvent.AttemptLatency = attemptLatency >= 0 ? attemptLatency : 0;
- apiAttemptEvent.Region = region;
- self.emit('apiCallAttempt', [apiAttemptEvent]);
- });
- request.addNamedListener('API_CALL_ATTEMPT_RETRY', 'retry', function API_CALL_ATTEMPT_RETRY() {
- var apiAttemptEvent = self.attemptFailEvent(request);
- apiAttemptEvent.Timestamp = attemptTimestamp;
- //attemptLatency may not be available if fail before response
- attemptLatency = attemptLatency ||
- Math.round(AWS.util.realClock.now() - attemptStartRealTime);
- apiAttemptEvent.AttemptLatency = attemptLatency >= 0 ? attemptLatency : 0;
- apiAttemptEvent.Region = region;
- self.emit('apiCallAttempt', [apiAttemptEvent]);
- });
- request.addNamedListener('API_CALL', 'complete', function API_CALL() {
- var apiCallEvent = self.apiCallEvent(request);
- apiCallEvent.AttemptCount = attemptCount;
- if (apiCallEvent.AttemptCount <= 0) return;
- apiCallEvent.Timestamp = callTimestamp;
- var latency = Math.round(AWS.util.realClock.now() - callStartRealTime);
- apiCallEvent.Latency = latency >= 0 ? latency : 0;
- var response = request.response;
- if (
- response.error &&
- response.error.retryable &&
- typeof response.retryCount === 'number' &&
- typeof response.maxRetries === 'number' &&
- (response.retryCount >= response.maxRetries)
- ) {
- apiCallEvent.MaxRetriesExceeded = 1;
- }
- self.emit('apiCall', [apiCallEvent]);
- });
- },
- /**
- * Override this method to setup any custom request listeners for each
- * new request to the service.
- *
- * @method_abstract This is an abstract method.
- */
- setupRequestListeners: function setupRequestListeners(request) {
- },
- /**
- * Gets the signing name for a given request
- * @api private
- */
- getSigningName: function getSigningName() {
- return this.api.signingName || this.api.endpointPrefix;
- },
- /**
- * Gets the signer class for a given request
- * @api private
- */
- getSignerClass: function getSignerClass(request) {
- var version;
- // get operation authtype if present
- var operation = null;
- var authtype = '';
- if (request) {
- var operations = request.service.api.operations || {};
- operation = operations[request.operation] || null;
- authtype = operation ? operation.authtype : '';
- }
- if (this.config.signatureVersion) {
- version = this.config.signatureVersion;
- } else if (authtype === 'v4' || authtype === 'v4-unsigned-body') {
- version = 'v4';
- } else if (authtype === 'bearer') {
- version = 'bearer';
- } else {
- version = this.api.signatureVersion;
- }
- return AWS.Signers.RequestSigner.getVersion(version);
- },
- /**
- * @api private
- */
- serviceInterface: function serviceInterface() {
- switch (this.api.protocol) {
- case 'ec2': return AWS.EventListeners.Query;
- case 'query': return AWS.EventListeners.Query;
- case 'json': return AWS.EventListeners.Json;
- case 'rest-json': return AWS.EventListeners.RestJson;
- case 'rest-xml': return AWS.EventListeners.RestXml;
- }
- if (this.api.protocol) {
- throw new Error('Invalid service `protocol\' ' +
- this.api.protocol + ' in API config');
- }
- },
- /**
- * @api private
- */
- successfulResponse: function successfulResponse(resp) {
- return resp.httpResponse.statusCode < 300;
- },
- /**
- * How many times a failed request should be retried before giving up.
- * the defaultRetryCount can be overriden by service classes.
- *
- * @api private
- */
- numRetries: function numRetries() {
- if (this.config.maxRetries !== undefined) {
- return this.config.maxRetries;
- } else {
- return this.defaultRetryCount;
- }
- },
- /**
- * @api private
- */
- retryDelays: function retryDelays(retryCount, err) {
- return AWS.util.calculateRetryDelay(retryCount, this.config.retryDelayOptions, err);
- },
- /**
- * @api private
- */
- retryableError: function retryableError(error) {
- if (this.timeoutError(error)) return true;
- if (this.networkingError(error)) return true;
- if (this.expiredCredentialsError(error)) return true;
- if (this.throttledError(error)) return true;
- if (error.statusCode >= 500) return true;
- return false;
- },
- /**
- * @api private
- */
- networkingError: function networkingError(error) {
- return error.code === 'NetworkingError';
- },
- /**
- * @api private
- */
- timeoutError: function timeoutError(error) {
- return error.code === 'TimeoutError';
- },
- /**
- * @api private
- */
- expiredCredentialsError: function expiredCredentialsError(error) {
- // TODO : this only handles *one* of the expired credential codes
- return (error.code === 'ExpiredTokenException');
- },
- /**
- * @api private
- */
- clockSkewError: function clockSkewError(error) {
- switch (error.code) {
- case 'RequestTimeTooSkewed':
- case 'RequestExpired':
- case 'InvalidSignatureException':
- case 'SignatureDoesNotMatch':
- case 'AuthFailure':
- case 'RequestInTheFuture':
- return true;
- default: return false;
- }
- },
- /**
- * @api private
- */
- getSkewCorrectedDate: function getSkewCorrectedDate() {
- return new Date(Date.now() + this.config.systemClockOffset);
- },
- /**
- * @api private
- */
- applyClockOffset: function applyClockOffset(newServerTime) {
- if (newServerTime) {
- this.config.systemClockOffset = newServerTime - Date.now();
- }
- },
- /**
- * @api private
- */
- isClockSkewed: function isClockSkewed(newServerTime) {
- if (newServerTime) {
- return Math.abs(this.getSkewCorrectedDate().getTime() - newServerTime) >= 300000;
- }
- },
- /**
- * @api private
- */
- throttledError: function throttledError(error) {
- // this logic varies between services
- if (error.statusCode === 429) return true;
- switch (error.code) {
- case 'ProvisionedThroughputExceededException':
- case 'Throttling':
- case 'ThrottlingException':
- case 'RequestLimitExceeded':
- case 'RequestThrottled':
- case 'RequestThrottledException':
- case 'TooManyRequestsException':
- case 'TransactionInProgressException': //dynamodb
- case 'EC2ThrottledException':
- return true;
- default:
- return false;
- }
- },
- /**
- * @api private
- */
- endpointFromTemplate: function endpointFromTemplate(endpoint) {
- if (typeof endpoint !== 'string') return endpoint;
- var e = endpoint;
- e = e.replace(/\{service\}/g, this.api.endpointPrefix);
- e = e.replace(/\{region\}/g, this.config.region);
- e = e.replace(/\{scheme\}/g, this.config.sslEnabled ? 'https' : 'http');
- return e;
- },
- /**
- * @api private
- */
- setEndpoint: function setEndpoint(endpoint) {
- this.endpoint = new AWS.Endpoint(endpoint, this.config);
- },
- /**
- * @api private
- */
- paginationConfig: function paginationConfig(operation, throwException) {
- var paginator = this.api.operations[operation].paginator;
- if (!paginator) {
- if (throwException) {
- var e = new Error();
- throw AWS.util.error(e, 'No pagination configuration for ' + operation);
- }
- return null;
- }
- return paginator;
- }
- });
- AWS.util.update(AWS.Service, {
- /**
- * Adds one method for each operation described in the api configuration
- *
- * @api private
- */
- defineMethods: function defineMethods(svc) {
- AWS.util.each(svc.prototype.api.operations, function iterator(method) {
- if (svc.prototype[method]) return;
- var operation = svc.prototype.api.operations[method];
- if (operation.authtype === 'none') {
- svc.prototype[method] = function (params, callback) {
- return this.makeUnauthenticatedRequest(method, params, callback);
- };
- } else {
- svc.prototype[method] = function (params, callback) {
- return this.makeRequest(method, params, callback);
- };
- }
- });
- },
- /**
- * Defines a new Service class using a service identifier and list of versions
- * including an optional set of features (functions) to apply to the class
- * prototype.
- *
- * @param serviceIdentifier [String] the identifier for the service
- * @param versions [Array<String>] a list of versions that work with this
- * service
- * @param features [Object] an object to attach to the prototype
- * @return [Class<Service>] the service class defined by this function.
- */
- defineService: function defineService(serviceIdentifier, versions, features) {
- AWS.Service._serviceMap[serviceIdentifier] = true;
- if (!Array.isArray(versions)) {
- features = versions;
- versions = [];
- }
- var svc = inherit(AWS.Service, features || {});
- if (typeof serviceIdentifier === 'string') {
- AWS.Service.addVersions(svc, versions);
- var identifier = svc.serviceIdentifier || serviceIdentifier;
- svc.serviceIdentifier = identifier;
- } else { // defineService called with an API
- svc.prototype.api = serviceIdentifier;
- AWS.Service.defineMethods(svc);
- }
- AWS.SequentialExecutor.call(this.prototype);
- //util.clientSideMonitoring is only available in node
- if (!this.prototype.publisher && AWS.util.clientSideMonitoring) {
- var Publisher = AWS.util.clientSideMonitoring.Publisher;
- var configProvider = AWS.util.clientSideMonitoring.configProvider;
- var publisherConfig = configProvider();
- this.prototype.publisher = new Publisher(publisherConfig);
- if (publisherConfig.enabled) {
- //if csm is enabled in environment, SDK should send all metrics
- AWS.Service._clientSideMonitoring = true;
- }
- }
- AWS.SequentialExecutor.call(svc.prototype);
- AWS.Service.addDefaultMonitoringListeners(svc.prototype);
- return svc;
- },
- /**
- * @api private
- */
- addVersions: function addVersions(svc, versions) {
- if (!Array.isArray(versions)) versions = [versions];
- svc.services = svc.services || {};
- for (var i = 0; i < versions.length; i++) {
- if (svc.services[versions[i]] === undefined) {
- svc.services[versions[i]] = null;
- }
- }
- svc.apiVersions = Object.keys(svc.services).sort();
- },
- /**
- * @api private
- */
- defineServiceApi: function defineServiceApi(superclass, version, apiConfig) {
- var svc = inherit(superclass, {
- serviceIdentifier: superclass.serviceIdentifier
- });
- function setApi(api) {
- if (api.isApi) {
- svc.prototype.api = api;
- } else {
- svc.prototype.api = new Api(api, {
- serviceIdentifier: superclass.serviceIdentifier
- });
- }
- }
- if (typeof version === 'string') {
- if (apiConfig) {
- setApi(apiConfig);
- } else {
- try {
- setApi(AWS.apiLoader(superclass.serviceIdentifier, version));
- } catch (err) {
- throw AWS.util.error(err, {
- message: 'Could not find API configuration ' +
- superclass.serviceIdentifier + '-' + version
- });
- }
- }
- if (!Object.prototype.hasOwnProperty.call(superclass.services, version)) {
- superclass.apiVersions = superclass.apiVersions.concat(version).sort();
- }
- superclass.services[version] = svc;
- } else {
- setApi(version);
- }
- AWS.Service.defineMethods(svc);
- return svc;
- },
- /**
- * @api private
- */
- hasService: function(identifier) {
- return Object.prototype.hasOwnProperty.call(AWS.Service._serviceMap, identifier);
- },
- /**
- * @param attachOn attach default monitoring listeners to object
- *
- * Each monitoring event should be emitted from service client to service constructor prototype and then
- * to global service prototype like bubbling up. These default monitoring events listener will transfer
- * the monitoring events to the upper layer.
- * @api private
- */
- addDefaultMonitoringListeners: function addDefaultMonitoringListeners(attachOn) {
- attachOn.addNamedListener('MONITOR_EVENTS_BUBBLE', 'apiCallAttempt', function EVENTS_BUBBLE(event) {
- var baseClass = Object.getPrototypeOf(attachOn);
- if (baseClass._events) baseClass.emit('apiCallAttempt', [event]);
- });
- attachOn.addNamedListener('CALL_EVENTS_BUBBLE', 'apiCall', function CALL_EVENTS_BUBBLE(event) {
- var baseClass = Object.getPrototypeOf(attachOn);
- if (baseClass._events) baseClass.emit('apiCall', [event]);
- });
- },
- /**
- * @api private
- */
- _serviceMap: {}
- });
- AWS.util.mixin(AWS.Service, AWS.SequentialExecutor);
- /**
- * @api private
- */
- module.exports = AWS.Service;
|