Backend half
This commit is contained in:
+204
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Copyright 2012-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You
|
||||
* may not use this file except in compliance with the License. A copy of
|
||||
* the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is
|
||||
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
* ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
var AWS = require('./core');
|
||||
var inherit = AWS.util.inherit;
|
||||
var jmespath = require('jmespath');
|
||||
|
||||
/**
|
||||
* @api private
|
||||
*/
|
||||
function CHECK_ACCEPTORS(resp) {
|
||||
var waiter = resp.request._waiter;
|
||||
var acceptors = waiter.config.acceptors;
|
||||
var acceptorMatched = false;
|
||||
var state = 'retry';
|
||||
|
||||
acceptors.forEach(function(acceptor) {
|
||||
if (!acceptorMatched) {
|
||||
var matcher = waiter.matchers[acceptor.matcher];
|
||||
if (matcher && matcher(resp, acceptor.expected, acceptor.argument)) {
|
||||
acceptorMatched = true;
|
||||
state = acceptor.state;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!acceptorMatched && resp.error) state = 'failure';
|
||||
|
||||
if (state === 'success') {
|
||||
waiter.setSuccess(resp);
|
||||
} else {
|
||||
waiter.setError(resp, state === 'retry');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api private
|
||||
*/
|
||||
AWS.ResourceWaiter = inherit({
|
||||
/**
|
||||
* Waits for a given state on a service object
|
||||
* @param service [Service] the service object to wait on
|
||||
* @param state [String] the state (defined in waiter configuration) to wait
|
||||
* for.
|
||||
* @example Create a waiter for running EC2 instances
|
||||
* var ec2 = new AWS.EC2;
|
||||
* var waiter = new AWS.ResourceWaiter(ec2, 'instanceRunning');
|
||||
*/
|
||||
constructor: function constructor(service, state) {
|
||||
this.service = service;
|
||||
this.state = state;
|
||||
this.loadWaiterConfig(this.state);
|
||||
},
|
||||
|
||||
service: null,
|
||||
|
||||
state: null,
|
||||
|
||||
config: null,
|
||||
|
||||
matchers: {
|
||||
path: function(resp, expected, argument) {
|
||||
try {
|
||||
var result = jmespath.search(resp.data, argument);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return jmespath.strictDeepEqual(result,expected);
|
||||
},
|
||||
|
||||
pathAll: function(resp, expected, argument) {
|
||||
try {
|
||||
var results = jmespath.search(resp.data, argument);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Array.isArray(results)) results = [results];
|
||||
var numResults = results.length;
|
||||
if (!numResults) return false;
|
||||
for (var ind = 0 ; ind < numResults; ind++) {
|
||||
if (!jmespath.strictDeepEqual(results[ind], expected)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
pathAny: function(resp, expected, argument) {
|
||||
try {
|
||||
var results = jmespath.search(resp.data, argument);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Array.isArray(results)) results = [results];
|
||||
var numResults = results.length;
|
||||
for (var ind = 0 ; ind < numResults; ind++) {
|
||||
if (jmespath.strictDeepEqual(results[ind], expected)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
status: function(resp, expected) {
|
||||
var statusCode = resp.httpResponse.statusCode;
|
||||
return (typeof statusCode === 'number') && (statusCode === expected);
|
||||
},
|
||||
|
||||
error: function(resp, expected) {
|
||||
if (typeof expected === 'string' && resp.error) {
|
||||
return expected === resp.error.code;
|
||||
}
|
||||
// if expected is not string, can be boolean indicating presence of error
|
||||
return expected === !!resp.error;
|
||||
}
|
||||
},
|
||||
|
||||
listeners: new AWS.SequentialExecutor().addNamedListeners(function(add) {
|
||||
add('RETRY_CHECK', 'retry', function(resp) {
|
||||
var waiter = resp.request._waiter;
|
||||
if (resp.error && resp.error.code === 'ResourceNotReady') {
|
||||
resp.error.retryDelay = (waiter.config.delay || 0) * 1000;
|
||||
}
|
||||
});
|
||||
|
||||
add('CHECK_OUTPUT', 'extractData', CHECK_ACCEPTORS);
|
||||
|
||||
add('CHECK_ERROR', 'extractError', CHECK_ACCEPTORS);
|
||||
}),
|
||||
|
||||
/**
|
||||
* @return [AWS.Request]
|
||||
*/
|
||||
wait: function wait(params, callback) {
|
||||
if (typeof params === 'function') {
|
||||
callback = params; params = undefined;
|
||||
}
|
||||
|
||||
if (params && params.$waiter) {
|
||||
params = AWS.util.copy(params);
|
||||
if (typeof params.$waiter.delay === 'number') {
|
||||
this.config.delay = params.$waiter.delay;
|
||||
}
|
||||
if (typeof params.$waiter.maxAttempts === 'number') {
|
||||
this.config.maxAttempts = params.$waiter.maxAttempts;
|
||||
}
|
||||
delete params.$waiter;
|
||||
}
|
||||
|
||||
var request = this.service.makeRequest(this.config.operation, params);
|
||||
request._waiter = this;
|
||||
request.response.maxRetries = this.config.maxAttempts;
|
||||
request.addListeners(this.listeners);
|
||||
|
||||
if (callback) request.send(callback);
|
||||
return request;
|
||||
},
|
||||
|
||||
setSuccess: function setSuccess(resp) {
|
||||
resp.error = null;
|
||||
resp.data = resp.data || {};
|
||||
resp.request.removeAllListeners('extractData');
|
||||
},
|
||||
|
||||
setError: function setError(resp, retryable) {
|
||||
resp.data = null;
|
||||
resp.error = AWS.util.error(resp.error || new Error(), {
|
||||
code: 'ResourceNotReady',
|
||||
message: 'Resource is not in the state ' + this.state,
|
||||
retryable: retryable
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads waiter configuration from API configuration
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
loadWaiterConfig: function loadWaiterConfig(state) {
|
||||
if (!this.service.api.waiters[state]) {
|
||||
throw new AWS.util.error(new Error(), {
|
||||
code: 'StateNotFoundError',
|
||||
message: 'State ' + state + ' not found.'
|
||||
});
|
||||
}
|
||||
|
||||
this.config = AWS.util.copy(this.service.api.waiters[state]);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user