iothub-explorer/iothub-explorer-simulate-de...

230 строки
8.8 KiB
JavaScript
Исходник Постоянная ссылка Обычный вид История

#!/usr/bin/env node
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
'use strict';
// Native packages
var fs = require('fs');
var path = require('path');
// External dependencies
var program = require('commander');
var prettyjson = require('prettyjson');
// Azure IoT SDK dependencies
var DeviceClient = require('azure-iot-device').Client;
var DeviceConnectionString = require('azure-iot-device').ConnectionString;
var Registry = require('azure-iothub').Registry;
// Local dependencies
var packageJson = require('./package.json');
var inputError = require('./common.js').inputError;
var printSuccess = require('./common.js').printSuccess;
var serviceError = require('./common.js').serviceError;
var printErrorAndExit = require('./common.js').printErrorAndExit;
var getSas = require('./common.js').getSas;
var getHostFromSas = require('./common.js').getHostFromSas;
var createDeviceConnectionString = require('./common.js').createDeviceConnectionString;
var createMessageFromArgument = require('./common.js').createMessageFromArgument;
program
.version(packageJson.version)
.description('Simulate a device.')
.option('--device-connection-string <device-connection-string>', 'connection string to use for the device')
.option('-l, --login <iothub-connection-string>', 'use the connection string provided as argument to use to authenticate with your IoT Hub instance')
.option('--protocol <amqp|amqp-ws|http|mqtt|mqtt-ws>', 'protocol used to send and receive messages (defaults to amqp)', verifyProtocol)
.option('--send [message]', 'send a test message as a device. If the message is not specified, a default message will be used')
.option('--send-interval <interval-in-milliseconds>', 'interval to use between each message being sent (defaults to 1000ms)', parseInt)
.option('--send-count <message-count>', 'number of messages to send', parseInt)
.option('--receive', 'Receive cloud-to-device (C2D) messages as a device')
.option('-v, --verbose', 'shows all the information contained in the message received, including annotations and properties')
.option('--receive-count <message-count>', 'number of C2D messages to receive', parseInt)
.option('--settle <complete|abandon|reject>', 'indicate how the received C2D messages should be settled (defaults to \'complete\')', verifySettle)
.option('--upload-file <file-path>', 'upload a file from the simulated device')
.parse(process.argv);
function verifySettle(arg) {
if (!!arg && arg !== 'complete' && arg !== 'reject' && arg !== 'abandon') {
inputError('--settle can take only take one of the following values: \'complete\', \'reject\' or \'abandon\'');
} else {
return arg;
}
}
function verifyProtocol(arg) {
var lowerCaseArg = arg.toLowerCase();
if (lowerCaseArg !== 'amqp' && lowerCaseArg !== 'amqp-ws' && lowerCaseArg !== 'http' && lowerCaseArg !== 'mqtt') {
inputError('--protocol can take only take one of the following values: \'amqp\', \'amqp-ws\', \'mqtt\', \'mqtt-ws\' or \'http\'');
} else {
return lowerCaseArg;
}
}
var sas = getSas(program.login);
if(!program.deviceConnectionString && !sas) {
inputError('You must specify the device connection string (--device-connection-string) or the IoT Hub connection string (--login), or use the \'login\' command first.');
}
if(!program.deviceConnectionString && !program.args[0]) {
inputError('You must specify either a device connection string (--device-connection-string) or the IoT Hub connection string and a device id as first argument');
}
if (!program.send && !program.receive && !program.uploadFile) {
inputError('Nothing to do: please use --send, --receive or --uploadFile');
}
var settleMethod = program.settle || 'complete';
var protocolArg = program.protocol || 'amqp';
var Protocol;
switch(protocolArg) {
case 'amqp-ws':
Protocol = require('azure-iot-device-amqp').AmqpWs;
break;
case 'http':
Protocol = require('azure-iot-device-http').Http;
break;
case 'mqtt':
Protocol = require('azure-iot-device-mqtt').Mqtt;
if (settleMethod !== 'complete') {
inputError('Cannot ' + settleMethod + ' messages with MQTT: messages are automatically completed.');
}
break;
case 'mqtt-ws':
Protocol = require('azure-iot-device-mqtt').MqttWs;
if (settleMethod !== 'complete') {
inputError('Cannot ' + settleMethod + ' messages with MQTT: messages are automatically completed.');
}
break;
default:
Protocol = require('azure-iot-device-amqp').Amqp;
break;
}
var sendInterval = program.sendInterval || 1000;
var sendCount = program.sendCount || Number.MAX_SAFE_INTEGER;
var receiveCount = program.receiveCount || Number.MAX_SAFE_INTEGER;
var uploadFilePath = program.uploadFile;
var deviceConnectionString;
var deviceId = program.args[0];
if (!deviceId) {
deviceConnectionString = program.deviceConnectionString;
if(!deviceConnectionString) {
inputError('You must specify either a device connection string (--device-connection-string) or the IoT Hub connection string and a device id as first argument');
} else {
deviceId = DeviceConnectionString.parse(deviceConnectionString).DeviceId;
simulateDevice();
}
} else {
var registry = Registry.fromSharedAccessSignature(sas.toString());
registry.get(deviceId, function(err, deviceInfo) {
if (err) serviceError(err);
else {
var host = getHostFromSas(sas.toString());
deviceConnectionString = createDeviceConnectionString(deviceInfo, host);
}
simulateDevice();
});
}
function simulateDevice() {
if (!deviceConnectionString) throw new Error('Couldn\'t figure out device connection string');
if (!Protocol) throw new Error('Couldn\'t figure out protocol to connect to IoT Hub');
var sendRunning = !!program.send;
var receiveRunning = !!program.receive;
var uploadRunning = !!program.uploadFile;
var client = DeviceClient.fromConnectionString(deviceConnectionString, Protocol);
client.open(function(err) {
if (err) serviceError('Could not connect as device: ' + err.message);
if (program.send) {
var sendCounter = 0;
var sendItv = setInterval(function() {
var message = program.send === true ? createMessageFromArgument('Simulated message: #' + sendCounter) : createMessageFromArgument(program.send);
client.sendEvent(message, function(err) {
if (err) serviceError(err);
else {
printSuccess('Message #' + sendCounter + ' sent successfully');
sendCounter++;
if (sendCounter === sendCount) {
sendRunning = false;
clearInterval(sendItv);
}
}
});
}, sendInterval);
}
if (program.receive) {
var receiveCounter = 0;
var onMessage = function(msg) {
printSuccess('==================');
printSuccess('Message received:');
console.log(prettyjson.render(msg.data.toString()));
if (program.verbose) {
console.log('user-id: ' + msg.userId);
console.log('message-id: ' + msg.messageId);
console.log('correlation-id: ' + msg.correlationId);
}
if (msg.properties.count() > 0) {
printSuccess('--- properties ---');
msg.properties.propertyList.forEach(function(prop) {
console.log(prop.key + ': ' + prop.value);
});
}
printSuccess('==================');
receiveCounter++;
if (receiveCounter === receiveCount) {
receiveRunning = false;
client.removeListener('message', onMessage);
}
client[settleMethod](msg, function(err) {
if (err) serviceError('Could not ' + settleMethod + ' message: ' + err.message);
else {
printSuccess(settleMethod + ' message: Success');
}
});
};
client.on('message', onMessage);
}
if (uploadFilePath) {
fs.stat(uploadFilePath, function (err, fileStats) {
if (err) inputError('Cannot find: ' + program.uploadFile);
var fileStream = fs.createReadStream(uploadFilePath);
client.uploadToBlob(path.basename(uploadFilePath), fileStream, fileStats.size, function (err) {
if (err) {
printErrorAndExit('Cannot upload file: ' + err.constructor.name + ': ' + err.message);
} else {
printSuccess('Upload successful');
}
fileStream.destroy();
uploadRunning = false;
});
});
}
var taskInterval = setInterval(function() {
if (!sendRunning && !receiveRunning && !uploadRunning) {
printSuccess('Device simulation finished.');
client.close(function(err) {
if (err) serviceError(err);
else {
clearInterval(taskInterval);
process.exit(0);
}
});
}
}, 200);
});
}