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

suculent / thinx-device-api / #252646719

11 Mar 2022 06:54PM UTC coverage: 1.81%. Remained the same
#252646719

push

web-flow
Merge pull request #291 from suculent/thinx-swarm

fixes from production

2 of 589 branches covered (0.34%)

Branch coverage included in aggregate %.

0 of 37 new or added lines in 7 files covered. (0.0%)

137 existing lines in 5 files now uncovered.

33 of 1345 relevant lines covered (2.45%)

0.06 hits per line

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

0.8
/lib/thinx/database.js
1
// Database Manager
2

3
const Globals = require("./globals.js");
1✔
4
const app_config = Globals.app_config();
×
5
const fs = require("fs-extra");
×
6
module.exports = class Database {
×
7

8
        constructor() {
9
                this.nano = require("nano")(app_config.database_uri);
×
NEW
10
                console.log("✅ [info] Loaded module: Database");
×
11
        }
12

13
        nano() {
UNCOV
14
                return this.nano;
×
15
        }
16

17
        null_cb(err, body, header) {
18
                // only unexpected errors should be logged
UNCOV
19
                if (process.env.ENVIRONMENT === "test") {
×
20
                        // The database may already exist.
21
                        if (err.ststusCode !== 412) {
×
UNCOV
22
                                console.log(err, body, header);
×
23
                        }
24
                }
25
        }
26

27
        // Designated initalizer
28
        init(callback) {
29

NEW
30
                console.log("ℹ️ [info] Initializing databases...");
×
31

UNCOV
32
                let db_names = [
×
33
                        "devices", "builds", "users", "logs"
34
                ];
35

UNCOV
36
                this.nano.db.list((err, existing_dbs) => {
×
37

UNCOV
38
                        if ((typeof(existing_dbs) === "undefined") || (existing_dbs === null)) existing_dbs = [];
×
39

UNCOV
40
                        db_names.forEach((name) => {
×
41

42
                                if (existing_dbs.includes(name)) {
×
43
                                        console.log("DB", name, "already exists.");
×
UNCOV
44
                                        return;
×
45
                                }
46

NEW
47
                                console.log("ℹ️ [info] Creating database", name);
×
48

UNCOV
49
                                const dbprefix = Globals.prefix();
×
50

51
                                this.nano.db.create(dbprefix + "managed_" + name).then((/* body */) => {
×
52
                                        var couch_db = this.nano.db.use(dbprefix + "managed_" + name);
×
53
                                        this.injectDesign(couch_db, name, "/opt/thinx/thinx-device-api/design/design_" + name + ".json");
×
54
                                        this.injectReplFilter(couch_db, "/opt/thinx/thinx-device-api/design/filters_" + name + ".json");
×
NEW
55
                                        console.log(`ℹ️ [info] managed_${name} db is ready now.`);
×
56
                                }).catch((err2) => {
UNCOV
57
                                        this.handleDatabaseErrors(err2, "managed_" + name);
×
58
                                });
59
                        });
60

61
                        this.nano.db.list((err2, new_dbs) => {
×
62
                                if (typeof (callback) !== "undefined") {
×
UNCOV
63
                                        callback(err2, new_dbs);
×
64
                                } else {
UNCOV
65
                                        return new_dbs;
×
66
                                }
67
                        });
68

69
                        setTimeout(() => {
×
UNCOV
70
                                setInterval(this.compactDatabases, 3600 * 1000); // Compact databases once an hour        
×
71
                        }, 30000);
72
                        
73
                });
74
        }
75

76
        compactDatabases(opt_callback) {
77
                const prefix = Globals.prefix();
×
78
                this.nano = require("nano")(app_config.database_uri);
×
79
                this.nano.db.compact(prefix + "managed_logs");
×
80
                this.nano.db.compact(prefix + "managed_builds");
×
81
                this.nano.db.compact(prefix + "managed_devices");
×
82
                this.nano.db.compact(prefix + "managed_users", "owners_by_username", (err) => {
×
83
                        if (err) {
×
UNCOV
84
                                if (typeof(opt_callback) !== "undefined") opt_callback(err);
×
85
                        } else {
86
                                console.log("» Database compact jobs completed.");
×
UNCOV
87
                                if (typeof(opt_callback) !== "undefined") opt_callback(true);
×
88
                        }
89
                });
90
        }
91

92
        // Database preparation on first run
93
        getDocument(file) {
94
                if (!fs.existsSync(file)) {
×
95
                        console.log("Initializing replication filter failed, file does not exist", file);
×
UNCOV
96
                        return false;
×
97
                }
98
                const data = fs.readFileSync(file);
×
99
                if (typeof (data) === "undefined") {
×
100
                        console.log("» [getDocument] no data read.");
×
UNCOV
101
                        return false;
×
102
                }
103
                // Parser may fail
104
                try {
×
UNCOV
105
                        return JSON.parse(data);
×
106
                } catch (e) {
107
                        console.log("» Document File may not exist: " + e);
×
UNCOV
108
                        return false;
×
109
                }
110
        }
111

112
        logCouchError(err, body, header, tag) {
113
                if (err !== null) {
×
114
                        if (err.toString().indexOf("conflict") === -1) {
×
NEW
115
                                console.log("☣️ [error] Couch Init error: ", err, body, header, tag);
×
116
                        }
117
                        if (err.toString().indexOf("ENOTFOUND") !== -1) {
×
118
                                console.log("Critical DB integration error, exiting.");
×
UNCOV
119
                                process.exit(1);
×
120
                        }
121
                } else {
UNCOV
122
                        return;
×
123
                }
124
                if (typeof (body) !== "undefined") {
×
NEW
125
                        console.log("☣️ [error] Log Couch Insert body: " + body + " " + tag);
×
126
                }
127
                if (typeof (header) !== "undefined") {
×
NEW
128
                        console.log("☣️ [error] Log Couchd Insert header: " + header + " " + tag);
×
129
                }
130
        }
131

132
        injectDesign(db, design, file) {
133
                if (typeof (design) === "undefined") return;
×
134
                let design_doc = this.getDocument(file);
×
135
                if (design_doc != null) {
×
136
                        db.insert(design_doc, "_design/" + design, (err, body, header) => {
×
UNCOV
137
                                this.logCouchError(err, body, header, "init:design:" + design); // returns if no err
×
138
                        });
139
                } else {
NEW
140
                        console.log("☣️ [error] Design doc injection issue at " + file);
×
141
                }
142
        }
143

144
        injectReplFilter(db, file) {
145
                let filter_doc = this.getDocument(file);
×
146
                if (filter_doc !== false) {
×
147
                        db.insert(filter_doc, "_design/repl_filters", (err, body, header) => {
×
UNCOV
148
                                this.logCouchError(err, body, header, "init:repl:" + JSON.stringify(filter_doc)); // returns if no err
×
149
                        });
150
                } else {
NEW
151
                        console.log("☣️ [error] Filter doc injection issue (no doc) at " + file);
×
152
                }
153
        }
154

155
        handleDatabaseErrors(err, name) {
UNCOV
156
                if (err.toString().indexOf("the file already exists") !== -1) {
×
157
                        // silently fail, this is ok
158
                } else if (err.toString().indexOf("error happened") !== -1) {
×
NEW
159
                        console.log("🚫 [critical] Database connectivity issue. " + err.toString() + " URI: " + app_config.database_uri);
×
160
                        // give some time for DB to wake up until next try, also prevents too fast restarts...
161
                        setTimeout(() => {
×
UNCOV
162
                                process.exit(1);
×
163
                        }, 1000);
164
                } else {
NEW
165
                        console.log("🚫 [critical] Database " + name + " creation failed. " + err + " URI: " + app_config.database_uri);
×
166
                        setTimeout(() => {
×
UNCOV
167
                                process.exit(2);
×
168
                        }, 1000);
169
                }
170
        }
171
};
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