function handler()

in source/services/just-in-time-on-boarding/index.js [21:193]


function handler(event, context, callback) {
    const tag = `${lib}(${event.clientId}):`;
    console.log(tag, 'Event:', JSON.stringify(event, null, 2));

    // Get the certificate for the principal
    let _cert;
    // let _thingName;
    let _device;

    console.log(tag, 'First describe the certificate for the incoming principal.');
    iot.describeCertificate({
        certificateId: event.principalIdentifier
    })
        .promise()
        .catch(err => {
            if (err.code === 'ResourceNotFoundException') {
                console.log(tag, 'Sputnik does not support Just In Time Registration for now.');
                err.code = 'NoFail';
            }
            throw err;
        })
        .then(cert => {
            _cert = cert;
            console.log(tag, 'Found certificate:', _cert.certificateArn);

            return iot
                .listPrincipalThings({
                    principal: _cert.certificateDescription.certificateArn,
                    maxResults: 1
                })
                .promise()
                .then(data => {
                    if (data.things.length === 0) {
                        const newThingName = `sputnik-${shortid.generate()}`;
                        console.log(
                            tag,
                            'Cert is not attached to any thing. Create Sputnik Device with ThingName:',
                            newThingName
                        );
                        return addDevice({
                            deviceTypeId: 'UNKNOWN',
                            deviceBlueprintId: 'UNKNOWN',
                            thingName: newThingName,
                            name: newThingName
                        }).then(r => {
                            return iot
                                .describeThing({
                                    thingName: newThingName
                                })
                                .promise();
                        });
                    } else {
                        console.log(tag, 'Cert is attached to thing:', data.things[0]);
                        return iot
                            .describeThing({
                                thingName: data.things[0]
                            })
                            .promise();
                    }
                });
        })
        .then(thing => {
            console.log(tag, 'Found thing:', thing);

            const attributes = thing.attributes;
            if (attributes.iot_certificate_arn === _cert.certificateArn) {
                return thing;
            } else {
                attributes.iot_certificate_arn = _cert.certificateArn;
                console.log(tag, 'Updating the attributes:', attributes);
                return iot
                    .updateThing({
                        thingName: thing.thingName,
                        attributePayload: {
                            attributes: attributes,
                            merge: true
                        }
                    })
                    .promise()
                    .then(() => {
                        return iot
                            .describeThing({
                                thingName: thing.thingName
                            })
                            .promise();
                    });
            }
        })
        .then(thing => {
            console.log(tag, 'Fetch Sputnik Device.');
            return documentClient
                .get({
                    TableName: process.env.TABLE_DEVICES,
                    Key: {
                        thingId: thing.thingId
                    }
                })
                .promise()
                .then(device => {
                    if (!device.Item) {
                        console.log(tag, 'Device does not exist. Create it.');
                        return addDevice({
                            deviceTypeId: 'UNKNOWN',
                            deviceBlueprintId: 'UNKNOWN',
                            thingName: thing.thingName,
                            name: thing.thingName
                        }).then(r => {
                            return {
                                Item: r
                            };
                        });
                    } else {
                        return device;
                    }
                });
        })
        .then(device => {
            _device = device.Item;

            console.log(tag, 'Device:', _device);

            let newMomentTimestamp = moment(event.timestamp);
            let connectionState = {
                state: event.eventType,
                at: newMomentTimestamp.utc().format()
            };
            let updateParams = {
                TableName: process.env.TABLE_DEVICES,
                Key: {
                    thingId: _device.thingId
                },
                UpdateExpression: 'set #ua = :ua, #certArn = :certArn, #cS = :cS',
                ExpressionAttributeNames: {
                    '#ua': 'updatedAt',
                    '#certArn': 'certificateArn',
                    '#cS': 'connectionState'
                },
                ExpressionAttributeValues: {
                    ':ua': moment()
                        .utc()
                        .format(),
                    ':certArn': _cert.certificateDescription.certificateArn,
                    ':cS': connectionState
                }
            };

            console.log(tag, 'Check if the event timestamp is after existing one');

            if (_device && _device.hasOwnProperty('connectionState') && _device.connectionState.hasOwnProperty('at')) {
                let oldMomentTimestamp = moment(_device.connectionState.at);
                if (oldMomentTimestamp.isAfter(newMomentTimestamp)) {
                    console.log(tag, 'Skip update because MQTT messages are swapped');
                    console.log(tag, 'oldMomentTimestamp:', oldMomentTimestamp.utc().format());
                    console.log(tag, 'newMomentTimestamp:', newMomentTimestamp.utc().format());
                    return _device;
                }
            }

            return documentClient.update(updateParams).promise();
        })
        .then(result => {
            callback(null, null);
        })
        .catch(err => {
            console.log(tag, 'Error:', err, err.stack);
            if (err.code === 'NoFail') {
                callback(null, null);
            } else {
                callback(err, null);
            }
        });

}