serverless-spy
Version:
CDK-based library for writing elegant integration tests on AWS serverless architecture and an additional web console to monitor events in real time.
225 lines (210 loc) • 8.12 kB
JavaScript
/*
* Copyright 2015-2016 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.
*/
//
// Instantiate the AWS SDK and configuration objects. The AWS SDK for
// JavaScript (aws-sdk) is used for Cognito Identity/Authentication, and
// the AWS IoT SDK for JavaScript (aws-iot-device-sdk) is used for the
// WebSocket connection to AWS IoT and device shadow APIs.
//
var AWS = require('aws-sdk');
var AWSIoTData = require('aws-iot-device-sdk');
var AWSConfiguration = require('./aws-configuration.js');
console.log('Loaded AWS SDK for JavaScript and AWS IoT SDK for Node.js');
//
// Initialize our configuration.
//
AWS.config.region = AWSConfiguration.region;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: AWSConfiguration.poolId
});
//
// Keep track of whether or not we've registered the shadows used by this
// example.
//
var shadowsRegistered = false;
//
// Create the AWS IoT shadows object. Note that the credentials must be
// initialized with empty strings; when we successfully authenticate to
// the Cognito Identity Pool, the credentials will be dynamically updated.
//
const shadows = AWSIoTData.thingShadow({
//
// Set the AWS region we will operate in.
//
region: AWS.config.region,
//
//Set the AWS IoT Host Endpoint
//
host:AWSConfiguration.host,
//
// Use a random client ID.
//
clientId: 'temperature-control-browser-' + (Math.floor((Math.random() * 100000) + 1)),
//
// Connect via secure WebSocket
//
protocol: 'wss',
//
// Set the maximum reconnect time to 8 seconds; this is a browser application
// so we don't want to leave the user waiting too long for reconnection after
// re-connecting to the network/re-opening their laptop/etc...
//
maximumReconnectTimeMs: 8000,
//
// Enable console debugging information (optional)
//
debug: true,
//
// IMPORTANT: the AWS access key ID, secret key, and sesion token must be
// initialized with empty strings.
//
accessKeyId: '',
secretKey: '',
sessionToken: ''
});
//
// Update divs whenever we receive delta events from the shadows.
//
shadows.on('delta', function(name, stateObject) {
if (name === 'TemperatureStatus') {
document.getElementById('temperature-monitor-div').innerHTML = '<p>interior: ' + stateObject.state.intTemp + '</p>' +
'<p>exterior: ' + stateObject.state.extTemp + '</p>' +
'<p>state: ' + stateObject.state.curState + '</p>';
} else { // name === 'TemperatureControl'
var enabled = stateObject.state.enabled ? 'enabled' : 'disabled';
document.getElementById('temperature-control-div').innerHTML = '<p>setpoint: ' + stateObject.state.setPoint + '</p>' +
'<p>mode: ' + enabled + '</p>';
}
});
//
// Update divs whenever we receive status events from the shadows.
//
shadows.on('status', function(name, statusType, clientToken, stateObject) {
if (statusType === 'rejected') {
//
// If an operation is rejected it is likely due to a version conflict;
// request the latest version so that we synchronize with the shadow
// The most notable exception to this is if the thing shadow has not
// yet been created or has been deleted.
//
if (stateObject.code !== 404) {
console.log('resync with thing shadow');
var opClientToken = shadows.get(name);
if (opClientToken === null) {
console.log('operation in progress');
}
}
} else { // statusType === 'accepted'
if (name === 'TemperatureStatus') {
document.getElementById('temperature-monitor-div').innerHTML = '<p>interior: ' + stateObject.state.desired.intTemp + '</p>' +
'<p>exterior: ' + stateObject.state.desired.extTemp + '</p>' +
'<p>state: ' + stateObject.state.desired.curState + '</p>';
} else { // name === 'TemperatureControl'
var enabled = stateObject.state.desired.enabled ? 'enabled' : 'disabled';
document.getElementById('temperature-control-div').innerHTML = '<p>setpoint: ' + stateObject.state.desired.setPoint + '</p>' +
'<p> mode: ' + enabled + '</p>';
}
}
});
//
// Attempt to authenticate to the Cognito Identity Pool. Note that this
// example only supports use of a pool which allows unauthenticated
// identities.
//
var cognitoIdentity = new AWS.CognitoIdentity();
AWS.config.credentials.get(function(err, data) {
if (!err) {
console.log('retrieved identity: ' + AWS.config.credentials.identityId);
var params = {
IdentityId: AWS.config.credentials.identityId
};
cognitoIdentity.getCredentialsForIdentity(params, function(err, data) {
if (!err) {
//
// Update our latest AWS credentials; the MQTT client will use these
// during its next reconnect attempt.
//
shadows.updateWebSocketCredentials(data.Credentials.AccessKeyId,
data.Credentials.SecretKey,
data.Credentials.SessionToken);
} else {
console.log('error retrieving credentials: ' + err);
alert('error retrieving credentials: ' + err);
}
});
} else {
console.log('error retrieving identity:' + err);
alert('error retrieving identity: ' + err);
}
});
//
// Connect handler; update div visibility and fetch latest shadow documents.
// Register shadows on the first connect event.
//
window.shadowConnectHandler = function() {
console.log('connect');
document.getElementById("connecting-div").style.visibility = 'hidden';
document.getElementById("temperature-monitor-div").style.visibility = 'visible';
document.getElementById("temperature-control-div").style.visibility = 'visible';
//
// We only register our shadows once.
//
if (!shadowsRegistered) {
shadows.register('TemperatureStatus', {
persistentSubscribe: true
});
shadows.register('TemperatureControl', {
persistentSubscribe: true
});
shadowsRegistered = true;
}
//
// After connecting, wait for a few seconds and then ask for the
// current state of the shadows.
//
setTimeout(function() {
var opClientToken = shadows.get('TemperatureControl');
if (opClientToken === null) {
console.log('operation in progress');
}
opClientToken = shadows.get('TemperatureStatus');
if (opClientToken === null) {
console.log('operation in progress');
}
}, 3000);
};
//
// Reconnect handler; update div visibility.
//
window.shadowReconnectHandler = function() {
console.log('reconnect');
document.getElementById("connecting-div").style.visibility = 'visible';
document.getElementById("temperature-monitor-div").style.visibility = 'hidden';
document.getElementById("temperature-control-div").style.visibility = 'hidden';
};
//
// Install connect/reconnect event handlers.
//
shadows.on('connect', window.shadowConnectHandler);
shadows.on('reconnect', window.shadowReconnectHandler);
//
// Initialize divs.
//
document.getElementById('connecting-div').style.visibility = 'visible';
document.getElementById('temperature-control-div').style.visibility = 'hidden';
document.getElementById('temperature-monitor-div').style.visibility = 'hidden';
document.getElementById('connecting-div').innerHTML = '<p>attempting to connect to aws iot...</p>';
document.getElementById('temperature-control-div').innerHTML = '<p>getting latest status...</p>';
document.getElementById('temperature-monitor-div').innerHTML = '';