lambda-live-debugger
Version:
Debug Lambda functions locally like it is running in the cloud
111 lines (110 loc) • 3.37 kB
JavaScript
import * as iot from 'aws-iot-device-sdk';
import { splitMessageToChunks } from './utils/splitIoTMessage.mjs';
import { IoTClient, DescribeEndpointCommand } from '@aws-sdk/client-iot';
import { Logger } from './logger.mjs';
let device;
const chunks = new Map();
/**
* Get IoT endpoint
* @param param0
* @returns
*/
async function getIoTEndpoint({ region, credentials, }) {
const iot = new IoTClient({
region,
credentials,
});
const response = await iot.send(new DescribeEndpointCommand({
endpointType: 'iot:Data-ATS',
}));
if (!response.endpointAddress)
throw new Error('IoT Endpoint address not found');
return response.endpointAddress;
}
let connectedPromiseResolve;
const connectedPromise = new Promise((resolve) => {
connectedPromiseResolve = resolve;
});
/**
* Connect to IoT
* @param props
* @returns
*/
async function connect(props) {
const credentials = props?.credentialsProvider
? await props.credentialsProvider()
: undefined;
const endpoint = await getIoTEndpoint({
region: props?.region,
credentials,
});
device = new iot.device({
protocol: 'wss',
host: endpoint,
reconnectPeriod: 1,
keepalive: 60,
region: props?.region,
accessKeyId: credentials?.accessKeyId,
secretKey: credentials?.secretAccessKey,
sessionToken: credentials?.sessionToken,
});
if (props?.topic) {
device.subscribe(props.topic, { qos: 1 });
Logger.verbose('[IoT] Subscribed to topic ', props.topic);
}
device.on('connect', () => {
Logger.verbose('[IoT] Connected');
connectedPromiseResolve();
});
device.on('error', (err) => {
Logger.error('[IoT] Error', err);
});
device.on('close', () => {
Logger.verbose('[IoT] Closed');
});
device.on('reconnect', () => {
Logger.verbose('[IoT] Reconnecting...');
});
if (props?.onMessage) {
const messageReceived = (topic, buffer) => {
const chunk = JSON.parse(buffer.toString());
if (!chunk.id) {
throw new Error('Invalid fragment');
}
let pending = chunks.get(chunk.id);
if (!pending) {
pending = new Map();
chunks.set(chunk.id, pending);
}
pending.set(chunk.index, chunk);
if (pending.size === chunk.count) {
const data = [...pending.values()]
.sort((a, b) => a.index - b.index)
.map((item) => item.data)
.join('');
chunks.delete(chunk.id);
const evt = JSON.parse(data);
props.onMessage(evt);
}
};
device.on('message', messageReceived);
}
await connectedPromise;
return {
publish: async (payload, topic) => {
await connectedPromise;
for (const fragment of splitMessageToChunks(payload)) {
await new Promise((r) => {
device.publish(topic, JSON.stringify(fragment), {
qos: 1,
}, () => {
r();
});
});
}
},
};
}
export const IoTService = {
connect,
};