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

suculent / thinx-device-api / #252646970

27 Oct 2017 03:17PM UTC coverage: 12.466% (+1.3%) from 11.197%
#252646970

push

suculent
added support for displaying/exporting extended SigFox attributes

37 of 1808 branches covered (2.05%)

Branch coverage included in aggregate %.

735 of 4385 relevant lines covered (16.76%)

0.17 hits per line

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

9.45
/lib/thinx/devices.js
1
/** This THiNX-RTM API module is responsible for managing userlib records. */
2

3
var Devices = (function() {
1✔
4

5
        var app_config = require("../../conf/config.json");
1✔
6
        if (typeof(process.env.CIRCLE_USERNAME) !== "undefined") {
1!
7
                console.log("ยป Configuring for Circle CI...");
×
8
                app_config = require("../../conf/config-test.json");
×
9
        }
10
        var db = app_config.database_uri;
1✔
11

12
        var prefix = "";
1✔
13
        try {
1✔
14
                var pfx_path = app_config.project_root + '/conf/.thx_prefix';
1✔
15
                if (fs.existsSync(pfx_path)) {
1!
16
                        prefix = fs.readFileSync(pfx_path) + "_";
×
17
                }
18
        } catch (e) {
19
                //console.log(e);
20
        }
21

22
        var devicelib = require("nano")(db).use(prefix + "managed_devices");
1✔
23

24
        var fs = require("fs");
1✔
25
        var exec = require("child_process");
1✔
26
        var mkdirp = require("mkdirp");
1✔
27

28
        var alog = require("./audit");
1✔
29
        var deploy = require("./deployment");
1✔
30
        var watcher = require("./repository");
1✔
31
        var device = require("./device");
1✔
32
        var sources = require("./sources");
1✔
33
        var messenger = require("./messenger");
1✔
34

35
        var Rollbar = require("rollbar");
1✔
36

37
        var rollbar = new Rollbar({
1✔
38
                accessToken: "5505bac5dc6c4542ba3bd947a150cb55",
39
                handleUncaughtExceptions: true,
40
                handleUnhandledRejections: true
41
        });
42

43
        var watcher_callback = function(result) {
1✔
44
                if (typeof(result) !== "undefined") {
×
45
                        console.log("[devices] watcher_callback result: " + JSON.stringify(result));
×
46
                        if (result === false) {
×
47
                                console.log(
×
48
                                        "[devices] No change detected on repository so far."
49
                                );
50
                        } else {
51
                                console.log(
×
52
                                        "[devices] CHANGE DETECTED! - TODO: Commence re-build (will notify user but needs to get all required user data first (owner/device is in path)"
53
                                );
54
                        }
55
                } else {
56
                        console.log("[devices] watcher_callback: no result");
×
57
                }
58
        };
59

60
        // public
61
        var _public = {
1✔
62
                list: function(owner, callback) {
63
                        devicelib.view("devicelib", "devices_by_owner", {
×
64
                                        "key": owner,
65
                                        "include_docs": false
66
                                },
67
                                function(err, body) {
68

69
                                        if (err) {
×
70
                                                if ((err.indexOf("Error: missing") !== -1) && typeof(callback) !== "undefined") {
×
71
                                                        callback(false, "none");
×
72
                                                }
73
                                                console.log("/api/user/devices: Error: " + err.toString());
×
74
                                                return;
×
75
                                        }
76

77
                                        var rows = body.rows; // devices returned
×
78
                                        var devices = [];
×
79
                                        for (var row in rows) {
×
80
                                                var rowData = rows[row];
×
81
                                                var dvc = rowData.value;
×
82

83
                                                if (typeof(dvc.source) === "undefined") {
×
84
                                                        dvc.source = null;
×
85
                                                }
86

87
                                                var platform = "unknown";
×
88
                                                if (typeof(dvc.platform) !== "undefined") {
×
89
                                                        platform = dvc.platform;
×
90
                                                }
91

92
                                                if (typeof(dvc.tags) === "undefined") {
×
93
                                                        dvc.tags = [];
×
94
                                                }
95

96
                                                var deviceDescriptor = {
×
97
                                                        udid: dvc.udid,
98
                                                        mac: device.normalizedMAC(dvc.mac),
99
                                                        firmware: dvc.firmware,
100
                                                        alias: dvc.alias,
101
                                                        owner: dvc.owner,
102
                                                        version: dvc.version,
103
                                                        lastupdate: dvc.lastupdate,
104
                                                        source: dvc.source,
105
                                                        platform: platform,
106
                                                        keyhash: dvc.keyhash,
107
                                                        auto_update: dvc.auto_update,
108
                                                        description: dvc.description,
109
                                                        tags: dvc.tags,
110
                                                        category: dvc.category,
111
                                                        icon: dvc.icon,
112
                                                        lat: dvc.lat,
113
                                                        lon: dvc.lon,
114
                                                        status: dvc.status,
115
                                                        snr: dvc.snr,
116
                                                        station: dvc.station
117
                                                };
118

119
                                                devices.push(deviceDescriptor);
×
120
                                        }
121
                                        callback(true, {
×
122
                                                success: true,
123
                                                devices: devices
124
                                        });
125
                                });
126
                },
127

128
                attach: function(owner, body, callback) {
129

130
                        if (typeof(body.source_id) === "undefined") {
×
131
                                callback(false, "missing_source_id");
×
132
                                return;
×
133
                        }
134

135
                        if (typeof(body.udid) === "undefined") {
×
136
                                callback(false, "missing_udid");
×
137
                                return;
×
138
                        }
139

140
                        console.log("[devices][attach] body: " + JSON.stringify(body));
×
141

142
                        var source_id = body.source_id;
×
143
                        var udid = body.udid;
×
144

145
                        console.log("Attach " + source_id + " to " + udid);
×
146

147
                        alog.log(owner, "Attempt to attach repository: " + source_id +
×
148
                                " to device: " + udid);
149

150
                        console.log("[OID:" + owner + "] [DEVICE_ATTACH] " + udid);
×
151

152
                        devicelib.get(udid, function(err, body) {
×
153

154
                                if (err) {
×
155
                                        console.log("find error: " + err);
×
156
                                        return;
×
157
                                }
158

159
                                console.log("Got device document body: " + JSON.stringify(body));
×
160

161
                                if (typeof(body) === "undefined") {
×
162
                                        callback(false, "udid_not_found:" + udid);
×
163
                                        alog.log(owner,
×
164
                                                "Attempt to attach repository to non-existent device: " +
165
                                                udid);
166
                                        return;
×
167
                                }
168

169
                                // TODO: FIXME: Support batch ops here
170
                                var doc = body;
×
171
                                var docstring = JSON.stringify(doc);
×
172

173
                                alog.log(doc.owner, "Attaching repository to device: " +
×
174
                                        docstring);
175
                                console.log("Attaching repository to device: " +
×
176
                                        docstring);
177

178
                                deploy.initWithOwner(doc.owner);
×
179
                                var repo_path = deploy.pathForDevice(doc.owner, doc.udid);
×
180
                                console.log(
×
181
                                        "[ATTACH] repo_path: " + repo_path);
182

183
                                mkdirp(repo_path, function(err) {
×
184
                                        if (err) console.error(err);
×
185
                                        else console.log("[ATTACH] " + repo_path + " created.");
×
186
                                });
187

188
                                doc.source = source_id;
×
189

190
                                devicelib.destroy(doc._id, doc._rev, function(err) {
×
191
                                        delete doc._rev;
×
192
                                        devicelib.insert(doc, doc.udid, function(err, body,
×
193
                                                header) {
194
                                                if (err) {
×
195
                                                        console.log("/api/device/attach ERROR:" + err);
×
196
                                                        callback(false, "attach_failed");
×
197
                                                        return;
×
198
                                                } else {
199
                                                        console.log("INSERT: " + JSON.stringify(body));
×
200
                                                        callback(true, source_id);
×
201
                                                }
202

203
                                                console.log(
×
204
                                                        "Warning: devices.js uses deprecated repository watcher instead of recommended webhooks."
205
                                                );
206

207
                                                if (fs.existsSync(repo_path)) {
×
208

209
                                                        sources.list(owner, function(success, response) {
×
210

211
                                                                if (success === true) {
×
212

213
                                                                        var all_sources = response;
×
214
                                                                        console.log(JSON.stringify(all_sources));
×
215
                                                                        var source = all_sources[source_id];
×
216

217
                                                                        // in case repo_path is is empty
218
                                                                        var GIT_PREFETCH = "bash -c \"cd " + repo_path +
×
219
                                                                                "; git clone " + source.url +
220
                                                                                "; pushd *; git submodule update --init --recursive; popd\"";
221
                                                                        var nochange = "Already up-to-date.";
×
222
                                                                        var temp = exec.execSync(GIT_PREFETCH).toString().replace(
×
223
                                                                                "\n", "");
224
                                                                        console.log("git prefetch result: " + temp);
×
225

226
                                                                } else {
227
                                                                        //
228
                                                                        console.log(
×
229
                                                                                "Unexpected 'Source List' in 'Device Attach' error!");
230
                                                                }
231

232
                                                        });
233

234
                                                        watcher.watchRepository(repo_path,
×
235
                                                                watcher_callback);
236
                                                } else {
237
                                                        console.log("[ATTACH+WATCH] " + repo_path +
×
238
                                                                " is not a directory.");
239
                                                }
240
                                        });
241
                                });
242
                        });
243
                },
244

245
                detach: function(owner, body, callback) {
246

247
                        if (typeof(body) === "undefined") {
×
248
                                callback(false, "missing_body");
×
249
                                return;
×
250
                        }
251

252
                        if (typeof(body.udid) === "undefined") {
×
253
                                callback(false, "missing_udid");
×
254
                                return;
×
255
                        }
256

257
                        console.log("Detach request body: " + JSON.stringify(body));
×
258

259
                        var udid = body.udid;
×
260

261
                        alog.log(owner, "Attempt to detach repository from device: " + udid);
×
262

263
                        devicelib.view("devicelib", "devices_by_udid", {
×
264
                                "key": udid,
265
                                "include_docs": true
266
                        }, function(err, body) {
267

268
                                if (err) {
×
269
                                        console.log("ERRO:" + err);
×
270
                                        return;
×
271
                                }
272

273
                                var rows = body.rows[0];
×
274
                                if (typeof(rows) !== "undefined") {
×
275
                                        console.log("DETACH rows: " + JSON.stringify(rows));
×
276
                                } else {
277
                                        callback(false, "udid_not_found(1):" + udid);
×
278
                                        return;
×
279
                                }
280

281
                                var doc;
282
                                console.log("BODY ROWS2: " + JSON.stringify(body.rows[0]));
×
283

284
                                if (typeof(body.rows[0]) === "undefined") {
×
285
                                        callback(false, "device_not_found(2):" + udid);
×
286
                                        return;
×
287
                                }
288

289
                                // TODO: FIXME: Support batch ops here
290
                                doc = body.rows[0].value;
×
291

292
                                console.log("Detaching repository from device: " + JSON.stringify(
×
293
                                        doc.udid));
294

295
                                var repo_path = deploy.pathForDevice(doc.owner, doc.udid);
×
296
                                console.log("repo_path: " + repo_path);
×
297

298
                                if (fs.existsSync(repo_path)) {
×
299
                                        watcher.unwatchRepository(repo_path);
×
300
                                }
301

302
                                devicelib.destroy(doc._id, doc._rev, function(err) {
×
303

304
                                        delete doc._rev;
×
305
                                        doc.source = null;
×
306

307
                                        devicelib.insert(doc, doc.udid, function(err, body,
×
308
                                                header) {
309
                                                if (err) {
×
310
                                                        console.log("/api/device/detach ERROR:" + err);
×
311
                                                        callback(false, "detach_failed");
×
312
                                                        return;
×
313
                                                } else {
314
                                                        callback(true, false);
×
315
                                                }
316
                                        });
317
                                });
318
                        });
319
                },
320

321
                revoke: function(owner, body, callback) {
322

323
                        // Global Method
324

325
                        function destroy_device(id, rev, owner, destroy_callback) {
326
                                var logmessage = "Revoking device: " + JSON.stringify(id);
×
327
                                alog.log(
×
328
                                        owner, logmessage);
329

330
                                devicelib.destroy(id, rev, function(err) {
×
331

332
                                        if (err) {
×
333
                                                console.log(err);
×
334
                                                if (typeof(destroy_callback) !== "undefined") destroy_callback(
×
335
                                                        false,
336
                                                        "revocation_failed");
337
                                                return;
×
338

339
                                        } else {
340

341
                                                var passwords_path = app_config.project_root + "/mqtt_passwords";
×
342

343
                                                var TOOL = exec.execSync("which mosquitto_passwd").toString().replace(
×
344
                                                        "\n", "");
345

346
                                                console.log("mosquitto_passwd detection result: " + TOOL);
×
347

348
                                                if (TOOL.length > "mosquitto_passwd".length) {
×
349

350
                                                        if (fs.existsSync(passwords_path)) {
×
351
                                                                var CMD = TOOL + " -D " + passwords_path + " " + id;
×
352
                                                                var temp = exec.execSync(CMD);
×
353
                                                                if (temp) {
×
354
                                                                        // console.log("[REVOKE_ERROR] MQTT: " + temp);
355
                                                                }
356
                                                                console.log("[OID:" + owner +
×
357
                                                                        "] [DEVICE_REVOCATION] " +
358
                                                                        id);
359
                                                                alog.log(owner, logmessage);
×
360

361
                                                                if (typeof(destroy_callback) !== "undefined") destroy_callback(
×
362
                                                                        true, id);
363
                                                        }
364
                                                }
365
                                        }
366
                                });
367
                        }
368

369
                        // Implementation
370

371
                        var udids;
372

373
                        if (typeof(body.udid) === "undefined") {
×
374
                                if (typeof(body.udids) === "undefined") {
×
375
                                        callback(false, "missing_udids");
×
376
                                        return;
×
377
                                } else {
378
                                        udids = body.udids;
×
379
                                }
380
                        } else {
381
                                udids = [body.udid];
×
382
                        }
383

384
                        alog.log(owner, "Attempt to revoke devices: " + JSON.stringify(udids));
×
385

386
                        devicelib.view("devicelib", "devices_by_owner", {
×
387
                                        "key": owner,
388
                                        "include_docs": true
389
                                },
390
                                function(err, body) {
391

392
                                        if (err) {
×
393
                                                console.log(err);
×
394
                                                callback(false, err);
×
395
                                                return;
×
396
                                        }
397

398
                                        if (body.rows.count === 0) {
×
399
                                                alog.log(owner, "No devices for owner.");
×
400
                                                callback(false, "no_device_for_owner");
×
401
                                                return;
×
402
                                        }
403

404
                                        //console.log("Device revocation: BODY ROWS3: " + JSON.stringify(body.rows[0]));
405

406
                                        if (typeof(body.rows[0]) === "undefined") {
×
407
                                                callback(false, "devices_not_found:" + JSON.stringify(udids));
×
408
                                                return;
×
409
                                        }
410

411
                                        var doc;
412
                                        var devices = body.rows;
×
413
                                        var devices_for_revocation = [];
×
414

415
                                        for (var dindex in body.rows) {
×
416
                                                var device = body.rows[dindex].value;
×
417
                                                var device_udid = device.udid;
×
418
                                                if (udids.toString().indexOf(device_udid) !== -1) {
×
419
                                                        devices_for_revocation.push(device);
×
420
                                                }
421
                                        }
422

423
                                        console.log("Devices for revocation: " + JSON.stringify(
×
424
                                                devices_for_revocation));
425

426
                                        // Simple/Group delete
427
                                        if (devices_for_revocation.count === 0) {
×
428
                                                callback(false, "devices_not_found");
×
429
                                                return;
×
430

431
                                        } else if (devices_for_revocation.count == 1) {
×
432
                                                doc = body.rows[0];
×
433
                                                console.log("Destroying single device: " + doc.udid);
×
434
                                                destroy_device(doc._id, doc._rev, owner, function(err, status) {
×
435
                                                        console.log("Simple destroy: " + err + " status: " + status);
×
436
                                                        callback(true, doc._id);
×
437
                                                });
438
                                                return;
×
439

440
                                        } else {
441

442
                                                for (var gindex in devices_for_revocation) {
×
443
                                                        doc = devices_for_revocation[gindex];
×
444
                                                        console.log("Destroying multiple devices at " + gindex + ": " +
×
445
                                                                JSON.stringify(doc.udid));
446
                                                        if (dindex < devices.count) {
×
447
                                                                destroy_device(doc.udid, doc._rev, owner);
×
448
                                                        } else {
449
                                                                console.log("Destroying last device: " + doc.udid);
×
450
                                                                destroy_device(doc.udid, doc._rev, owner); // callback shall be undefined
×
451
                                                        }
452
                                                }
453
                                        }
454

455
                                        callback(true, "async_progress");
×
456

457
                                });
458
                },
459

460
                // Push configuration to one or more devices (store and use MQTT)
461
                push: function(owner, body, callback) {
462
                        var udids;
463
                        var msgr = messenger.initWithOwner(owner, null /* no socket */ ,
×
464
                                function(error,
465
                                        response) {
466
                                        if (typeof(body.udid) === "undefined") {
×
467
                                                if (typeof(body.udids) === "undefined") {
×
468
                                                        callback(false, "missing_udids");
×
469
                                                        return;
×
470
                                                } else {
471
                                                        udids = body.udids;
×
472
                                                }
473
                                        } else {
474
                                                udids = [body.udid];
×
475
                                        }
476
                                        for (var dindex in udids) {
×
477
                                                messenger.publish(owner, udids[dindex], {
×
478
                                                        configuration: body.enviros
479
                                                });
480
                                        }
481
                                        callback(true, "pushing_configuration");
×
482
                                });
483
                }
484
        };
485

486
        return _public;
1✔
487

488
})();
489

490
exports.list = Devices.list;
1✔
491
exports.attach = Devices.attach;
1✔
492
exports.detach = Devices.detach;
1✔
493
exports.push = Devices.push;
1✔
494
exports.revoke = Devices.revoke;
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

© 2026 Coveralls, Inc