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

telefonicaid / iotagent-node-lib / 18165933486

01 Oct 2025 02:42PM UTC coverage: 79.318% (-0.001%) from 79.319%
18165933486

Pull #1734

github

web-flow
Merge 04824d46d into fd0c311cb
Pull Request #1734: allow use commands by simple subscriptions/notifications

2038 of 2743 branches covered (74.3%)

Branch coverage included in aggregate %.

89 of 110 new or added lines in 10 files covered. (80.91%)

10 existing lines in 1 file now uncovered.

3914 of 4761 relevant lines covered (82.21%)

281.13 hits per line

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

68.63
/lib/services/ngsi/subscription-NGSI-v2.js
1
/*
2
 * Copyright 2020 Telefonica Investigación y Desarrollo, S.A.U
3
 *
4
 * This file is part of fiware-iotagent-lib
5
 *
6
 * fiware-iotagent-lib 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
 * fiware-iotagent-lib 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 fiware-iotagent-lib.
18
 * If not, see http://www.gnu.org/licenses/.
19
 *
20
 * For those usages not covered by the GNU Affero General Public License
21
 * please contact with::daniel.moranjimenez@telefonica.com
22
 *
23
 * Modified by: Federico M. Facca - Martel Innovate
24
 * Modified by: Daniel Calvo - ATOS Research & Innovation
25
 * Modified by: Jason Fox - FIWARE Foundation
26
 */
27

28
const errors = require('../../errors');
1✔
29
const logger = require('logops');
1✔
30
const config = require('../../commonConfig');
1✔
31
const utils = require('../northBound/restUtils');
1✔
32
const context = {
1✔
33
    op: 'IoTAgentNGSI.Subscription-v2'
34
};
35

36
/**
37
 * Generate a new subscription request handler using NGSIv2, based on the device and triggers given to the function.
38
 *
39
 * @param {Object} device       Object containing all the information about a particular device.
40
 * @param {Object} triggers     Array with the names of the attributes that would trigger the subscription.
41
 * @param {Boolean} store       If set, store the subscription result in the device. Otherwise, return the ID.
42
 * @param {Function} callback   Callback to be called when the subscription handler ends.
43
 * @return {Function}           Returns a request handler for the given data.
44
 */
45
function createSubscriptionHandlerNgsi2(device, triggers, store, callback) {
46
    return function (error, response, body) {
9✔
47
        if (error) {
9!
48
            logger.debug(
×
49
                context,
50
                'Transport error found subscribing device with id [%s] to entity [%s]',
51
                device.id,
52
                device.name
53
            );
54

55
            callback(error);
×
56
        } else if (response.statusCode !== 200 && response.statusCode !== 201) {
9!
57
            logger.debug(
×
58
                context,
59
                'Unknown error subscribing device with id [%s] to entity [%s]: $s',
60
                response.statusCode
61
            );
62

63
            callback(
×
64
                new errors.EntityGenericError(
65
                    device.name,
66
                    device.type,
67
                    device,
68
                    {
69
                        details: body
70
                    },
71
                    response.statusCode
72
                )
73
            );
74
        } else if (body && body.orionError) {
9!
75
            logger.debug(
×
76
                context,
77
                'Orion found subscribing device with id [%s] to entity [%s]: %s',
78
                device.id,
79
                device.name,
80
                body.orionError
81
            );
82

83
            callback(new errors.BadRequest(body.orionError.details));
×
84
        } else if (store) {
9✔
85
            if (!device.subscriptions) {
5!
86
                device.subscriptions = [];
5✔
87
            }
88

89
            device.subscriptions.push({
5✔
90
                id: response.headers.location.substr(response.headers.location.lastIndexOf('/') + 1),
91
                triggers
92
            });
93

94
            config.getRegistry().update(device, device, callback);
5✔
95
        } else {
96
            callback(null, {
4✔
97
                subscriptionId: response.headers.location.substr(response.headers.location.lastIndexOf('/') + 1)
98
            });
99
        }
100
    };
101
}
102

103
/**
104
 * Makes a subscription for the given device's entity using NGSIv2, triggered by the given attributes.
105
 * The contents of the notification can be selected using the "content" array (that can be left blank
106
 * to notify the complete entity).
107
 *
108
 * @param {Object} device       Object containing all the information about a particular device.
109
 * @param {Object} triggers     Array with the names of the attributes that would trigger the subscription
110
 * @param {Object} content      Array with the names of the attributes to retrieve in the notification.
111
 */
112
function subscribeNgsi2(device, triggers, content, attrsFormat, callback) {
113
    const options = {
9✔
114
        method: 'POST',
115
        headers: {
116
            'fiware-service': device.service,
117
            'fiware-servicepath': device.subservice
118
        },
119
        json: {
120
            description: 'Managed by IOTA: ' + device.name + ' ' + device.type + ' ' + triggers.join(','),
121
            subject: {
122
                entities: [
123
                    {
124
                        id: device.name,
125
                        type: device.type
126
                    }
127
                ],
128

129
                condition: {
130
                    attrs: triggers
131
                }
132
            },
133
            notification: {
134
                http: {
135
                    url: config.getConfig().providerUrl + '/notify'
136
                },
137
                attrs: content || [],
14✔
138
                attrsFormat: attrsFormat,
139
                onlyChangedAttrs: true
140
            }
141
        }
142
    };
143

144
    let store = true;
9✔
145

146
    if (content) {
9✔
147
        store = false;
4✔
148
    }
149

150
    if (device.cbHost && device.cbHost.indexOf('://') !== -1) {
9!
151
        options.uri = device.cbHost + '/v2/subscriptions';
×
152
    } else if (device.cbHost && device.cbHost.indexOf('://') === -1) {
9!
153
        options.uri = 'http://' + device.cbHost + '/v2/subscriptions';
×
154
    } else {
155
        options.uri = config.getConfig().contextBroker.url + '/v2/subscriptions';
9✔
156
    }
157
    utils.executeWithSecurity(options, device, createSubscriptionHandlerNgsi2(device, triggers, store, callback));
9✔
158
}
159

160
/**
161
 * Generate a new unsubscription request handler using NGSIv2, based on the device and subscription ID
162
 * given to the function.
163
 *
164
 * @param {Object} device       Object containing all the information about a particular device.
165
 * @param {String} id           ID of the subscription to remove.
166
 * @param {Function} callback   Callback to be called when the subscription handler ends.
167
 * @return {Function}           Returns a request handler for the given data.
168
 */
169
function createUnsubscribeHandlerNgsi2(device, id, callback) {
170
    return function (error, response, body) {
4✔
171
        if (error) {
4✔
172
            logger.debug(
1✔
173
                context,
174
                'Transport error found unsubscribing device with id [%s] to entity [%s]',
175
                device.id,
176
                device.name
177
            );
178

179
            callback(error);
1✔
180
        } else if (response.statusCode !== 204) {
3!
181
            logger.debug(
×
182
                context,
183
                'Unknown error unsubscribing device with id [%s] to entity [%s]: %s',
184
                device.id,
185
                device.name,
186
                response.statusCode
187
            );
188

189
            callback(
×
190
                new errors.EntityGenericError(
191
                    device.name,
192
                    device.type,
193
                    device,
194
                    {
195
                        details: body
196
                    },
197
                    response.statusCode
198
                )
199
            );
200
        } else if (body && body.orionError) {
3!
201
            logger.debug(
×
202
                context,
203
                'Orion found subscribing device with id [%s] to entity [%s]: %s',
204
                device.id,
205
                device.name,
206
                body.orionError
207
            );
208

209
            callback(new errors.BadRequest(body.orionError.details));
×
210
        } else {
211
            logger.debug(context, 'removing subscription %s from device %j', id, device);
3✔
212
            if (device.subscriptions) {
3✔
213
                // check before try to eliminates
214
                const index = device.subscriptions.indexOf(id);
2✔
215
                if (index !== -1) {
2!
216
                    // only eliminates if exits
NEW
217
                    device.subscriptions.splice(index, 1);
×
218
                }
219
            }
220
            config.getRegistry().update(device, device, callback);
3✔
221
        }
222
    };
223
}
224

225
/**
226
 * Remove the subscription with the given ID from the Context Broker and from the device repository using NGSIv2.
227
 *
228
 * @param {Object} device       Object containing all the information about a particular device.
229
 * @param {String} id           ID of the subscription to remove.
230
 */
231
function unsubscribeNgsi2(device, id, callback) {
232
    const options = {
4✔
233
        method: 'DELETE',
234
        headers: {
235
            'fiware-service': device.service,
236
            'fiware-servicepath': device.subservice
237
        }
238
    };
239

240
    if (device.cbHost && device.cbHost.indexOf('://') !== -1) {
4!
241
        options.uri = device.cbHost + '/v2/subscriptions/' + id;
×
242
    } else if (device.cbHost && device.cbHost.indexOf('://') === -1) {
4!
243
        options.uri = 'http://' + device.cbHost + '/v2/subscriptions/' + id;
×
244
    } else {
245
        options.uri = config.getConfig().contextBroker.url + '/v2/subscriptions/' + id;
4✔
246
    }
247
    utils.executeWithSecurity(options, device, createUnsubscribeHandlerNgsi2(device, id, callback));
4✔
248
}
249

250
exports.subscribe = subscribeNgsi2;
1✔
251
exports.unsubscribe = unsubscribeNgsi2;
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