• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

telefonicaid / iotagent-json / 6558328460

18 Oct 2023 08:34AM UTC coverage: 77.24%. Remained the same
6558328460

Pull #767

github

web-flow
Merge a29ef3d1e into 1346a3c11
Pull Request #767: remove placeholder from logs

364 of 540 branches covered (0.0%)

Branch coverage included in aggregate %.

20 of 20 new or added lines in 3 files covered. (100.0%)

834 of 1011 relevant lines covered (82.49%)

69.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.44
/lib/commandHandler.js
1
/*
2
 * Copyright 2016 Telefonica Investigación y Desarrollo, S.A.U
3
 *
4
 * This file is part of iotagent-json
5
 *
6
 * iotagent-json is free software: you can redistribute it and/or
7
 * modify it under the terms of the GNU Affero General Public License as
8
 * published by the Free Software Foundation, either version 3 of the License,
9
 * or (at your option) any later version.
10
 *
11
 * iotagent-json is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
 * See the GNU Affero General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public
17
 * License along with iotagent-json.
18
 * If not, seehttp://www.gnu.org/licenses/.
19
 *
20
 * For those usages not covered by the GNU Affero General Public License
21
 * please contact with::[contacto@tid.es]
22
 */
23

24
const async = require('async');
1✔
25
const iotAgentLib = require('iotagent-node-lib');
1✔
26
const iotaUtils = require('./iotaUtils');
1✔
27
const constants = require('./constants');
1✔
28
const transportSelector = require('./transportSelector');
1✔
29
const config = require('./configService');
1✔
30
const context = {
1✔
31
    op: 'IoTAgentJSON.Commands'
32
};
33

34
/**
35
 * Serializes a payload for a command depending on its payloadType if provided
36
 *
37
 * @param {String} payload          Payload to serialized
38
 * @param {Object} command          Command attribute
39
 * @return {Function}               Returns a serialized payload
40
 */
41
function serializedPayloadCommand(payload, command) {
42
    let serialized;
43
    if (command && command.payloadType) {
20✔
44
        switch (command.payloadType.toLowerCase()) {
8!
45
            case 'binaryfromstring':
46
                serialized = Buffer.from(payload.toString());
×
47
                break;
×
48
            case 'binaryfromhex':
49
                serialized = Buffer.from(payload, 'HEX');
3✔
50
                break;
3✔
51
            case 'binaryfromjson': // used by AMQP transport
52
                serialized = Buffer.from(JSON.stringify(payload));
4✔
53
                break;
4✔
54
            case 'text':
55
                serialized = payload;
1✔
56
                break;
1✔
57
            case 'json': // passthrough
58
            default:
59
                serialized = JSON.stringify(payload);
×
60
        }
61
    } else {
62
        serialized = JSON.stringify(payload);
12✔
63
    }
64
    return serialized;
20✔
65
}
66

67
/**
68
 * Generate a function that executes the given command in the device.
69
 *
70
 * @param {String} apiKey           APIKey of the device's service or default APIKey.
71
 * @param {Object} device           Object containing all the information about a device.
72
 * @param {Object} attribute        Attribute in NGSI format.
73
 * @return {Function}               Command execution function ready to be called with async.series.
74
 */
75
function generateCommandExecution(apiKey, device, attribute) {
76
    let payload = {};
20✔
77
    let command = device && device.commands.find((att) => att.name === attribute.name);
32✔
78
    if (command && command.expression) {
20✔
79
        let parser = iotAgentLib.dataPlugins.expressionTransformation;
10✔
80
        // The context for the JEXL expression should be the ID, TYPE, S, SS
81
        let attrList = iotAgentLib.dataPlugins.utils.getIdTypeServSubServiceFromDevice(device);
10✔
82
        attrList = device.staticAttributes
10!
83
            ? attrList.concat(device.staticAttributes).concat(attribute)
84
            : attrList.concat(attribute);
85
        let ctxt = parser.extractContext(attrList, device);
10✔
86
        // expression result will be the full command payload
87
        let payloadRes = null;
10✔
88
        try {
10✔
89
            payloadRes = parser.applyExpression(command.expression, ctxt, device);
10✔
90
        } catch (e) {
91
            // nothing to report
92
        }
93
        payload = payloadRes ? payloadRes : command.expression;
10!
94
    } else {
95
        payload[attribute.name] = attribute.value;
10✔
96
    }
97
    if (device.transport === 'AMQP') {
20✔
98
        // to ensure backward compability
99
        command.payloadType = command.payloadType ? command.payloadType : 'binaryfromjson';
4!
100
    }
101
    const serialized = serializedPayloadCommand(payload, command);
20✔
102
    const contentType = command && command.contentType ? command.contentType : 'application/json';
20!
103
    config
20✔
104
        .getLogger()
105
        .debug(
106
            context,
107
            'Sending command execution to device [%s] with apikey [%s] and payload [%j] ',
108
            device.id,
109
            apiKey,
110
            payload
111
        );
112

113
    const executions = transportSelector.createExecutionsForBinding(
20✔
114
        [apiKey, device, attribute.name, serialized, contentType],
115
        'executeCommand',
116
        device.transport || config.getConfig().defaultTransport
20!
117
    );
118

119
    return executions;
20✔
120
}
121

122
/**
123
 * Handles a command execution request coming from the Context Broker. This handler should:
124
 *  - Identify the device affected by the command.
125
 *  - Send the command to the appropriate MQTT topic.
126
 *  - Update the command status in the Context Broker.
127
 *
128
 * @param {String} id               ID of the entity for which the command execution was issued.
129
 * @param {String} type             Type of the entity for which the command execution was issued.
130
 * @param {String} service          Service ID.
131
 * @param {String} subservice       Subservice ID.
132
 * @param {Array} attributes        List of NGSI attributes of type command to execute.
133
 */
134
function commandHandler(id, type, service, subservice, attributes, callback) {
135
    config
20✔
136
        .getLogger()
137
        .debug(
138
            context,
139
            'Handling command %j for device [%s] in service [%s - %s]',
140
            attributes,
141
            id,
142
            service,
143
            subservice
144
        );
145

146
    function concat(previous, current) {
147
        previous = previous.concat(current);
20✔
148
        return previous;
20✔
149
    }
150

151
    iotAgentLib.getDeviceByNameAndType(id, type, service, subservice, function (error, device) {
20✔
152
        if (error) {
20!
153
            config.getLogger().error(
×
154
                context,
155

156
                "COMMAND-001: Command execution could not be handled, as device for entity [%s] [%s] wasn't found",
157

158
                id,
159
                type
160
            );
161
            callback(error);
×
162
        } else {
163
            iotaUtils.getEffectiveApiKey(device.service, device.subservice, device, function (error, apiKey) {
20✔
164
                if (error) {
20!
165
                    callback(error);
×
166
                } else {
167
                    async.series(
20✔
168
                        attributes.map(generateCommandExecution.bind(null, apiKey, device)).reduce(concat, []),
169
                        callback
170
                    );
171
                }
172
            });
173
        }
174
    });
175
}
176

177
/**
178
 * Process an update in the state of a command with information coming from the device.
179
 *
180
 * @param {String} apiKey           API Key corresponding to the Devices configuration.
181
 * @param {String} deviceId         Id of the device to be updated.
182
 * @param {Object} device           Device object containing all the information about a device.
183
 * @param {Object} messageObj       JSON object sent using MQTT.
184
 */
185
function updateCommand(apiKey, deviceId, device, messageObj) {
186
    const commandList = Object.keys(messageObj);
8✔
187
    const commandUpdates = [];
8✔
188

189
    for (let i = 0; i < commandList.length; i++) {
8✔
190
        commandUpdates.push(
8✔
191
            async.apply(
192
                iotAgentLib.setCommandResult,
193
                device.name,
194
                config.getConfig().iota.defaultResource,
195
                apiKey,
196
                commandList[i],
197
                messageObj[commandList[i]],
198
                constants.COMMAND_STATUS_COMPLETED,
199
                device
200
            )
201
        );
202
    }
203

204
    async.series(commandUpdates, function (error) {
8✔
205
        if (error) {
8!
206
            config.getLogger().error(
×
207
                context,
208

209
                "COMMANDS-002: Couldn't update command status in the Context broker " +
210
                    'for device [%s] with apiKey [%s]: %s',
211
                device.id,
212
                apiKey,
213
                error
214
            );
215
        } else {
216
            config
8✔
217
                .getLogger()
218
                .debug(
219
                    context,
220
                    'Single measure for device [%s] with apiKey [%s] successfully updated',
221
                    device.id,
222
                    apiKey
223
                );
224
        }
225
    });
226
}
227

228
exports.generateCommandExecution = generateCommandExecution;
1✔
229
exports.updateCommand = updateCommand;
1✔
230
exports.handler = commandHandler;
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc