@frangoteam/fuxa-min 1.2.11 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/api/auth/index.js +141 -3
  2. package/api/index.js +18 -2
  3. package/api/jwt-helper.js +3 -1
  4. package/api/resources/index.js +19 -2
  5. package/dist/3rdpartylicenses.txt +139 -7
  6. package/dist/assets/i18n/de.json +10 -0
  7. package/dist/assets/i18n/en.json +14 -3
  8. package/dist/assets/i18n/es.json +12 -0
  9. package/dist/assets/i18n/fr.json +10 -0
  10. package/dist/assets/i18n/ja.json +15 -6
  11. package/dist/assets/i18n/ko.json +12 -0
  12. package/dist/assets/i18n/pt.json +9 -2
  13. package/dist/assets/i18n/ru.json +11 -0
  14. package/dist/assets/i18n/sv.json +10 -1
  15. package/dist/assets/i18n/tr.json +8 -1
  16. package/dist/assets/i18n/ua.json +9 -2
  17. package/dist/assets/i18n/zh-cn.json +10 -0
  18. package/dist/assets/i18n/zh-tw.json +11 -1
  19. package/dist/index.html +2 -2
  20. package/dist/main.bafae830903d548e.js +329 -0
  21. package/dist/polyfills.d7de05f9af2fb559.js +1 -0
  22. package/dist/{runtime.8ef63094e52a66ba.js → runtime.9136a61a9b98f987.js} +1 -1
  23. package/dist/{scripts.40b60f02658462e4.js → scripts.d9e6ee984bf6f3b7.js} +1 -1
  24. package/dist/styles.545e37beb3e671ba.css +1 -0
  25. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-daq.html +56 -5
  26. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-daq.js +8 -2
  27. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-change.html +56 -5
  28. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-change.js +12 -12
  29. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-daq-settings.html +56 -5
  30. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-daq-settings.js +14 -10
  31. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag.html +56 -5
  32. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag.js +8 -2
  33. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag-daq-settings.html +56 -5
  34. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag-daq-settings.js +24 -20
  35. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag.html +56 -5
  36. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag.js +8 -2
  37. package/main.js +35 -17
  38. package/package.json +10 -5
  39. package/runtime/devices/adsclient/index.js +1 -1
  40. package/runtime/devices/ethernetip/index.js +1 -1
  41. package/runtime/devices/gpio/index.js +1 -1
  42. package/runtime/devices/odbc/index.js +5 -5
  43. package/runtime/devices/template/index.js +14 -14
  44. package/runtime/storage/daqstorage.js +28 -2
  45. package/runtime/storage/questdb/index.js +224 -0
  46. package/runtime/utils.js +5 -0
  47. package/settings.default.js +5 -2
  48. package/dist/main.92522279642ef880.js +0 -329
  49. package/dist/polyfills.c8e7db9850a3ad8b.js +0 -1
  50. package/dist/styles.03cc550382689976.css +0 -1
@@ -4,23 +4,72 @@
4
4
  color: '#a6bbcf',
5
5
  defaults: {
6
6
  name: {value:""},
7
- tag: {value:"", required:true}
7
+ tag: {value:""}, // Keep: tag name for display and backward compatibility
8
+ tagId: {value:""} // New: unique identifier (optional, for backward compatibility)
8
9
  },
9
10
  inputs:1,
10
11
  outputs:1,
11
12
  icon: "white-globe.png",
12
13
  label: function() {
13
- return this.name||this.tag||"set tag";
14
+ if (this.name) {
15
+ return this.name;
16
+ }
17
+ // Display tag name or tagId
18
+ return this.tag || this.tagId || "set tag";
14
19
  },
15
20
  oneditprepare: function() {
21
+ var node = this;
22
+ var tagMap = {}; // Use tag.id as key to avoid tag.name duplication issues
23
+
16
24
  $.getJSON('/nodered/fuxa/devices', function(data) {
17
25
  var datalist = $('#fuxa-tags-set');
18
26
  datalist.empty();
27
+
19
28
  data.forEach(function(device) {
20
29
  device.tags.forEach(function(tag) {
21
- datalist.append('<option value="' + tag.name + '">' + device.name + ' - ' + tag.name + '</option>');
30
+ var fullName = device.name + ' - ' + tag.name;
31
+ // datalist option value format: tag.name(tag.id)
32
+ var optionValue = tag.name + '(' + tag.id + ')';
33
+ datalist.append('<option value="' + optionValue + '">' + fullName + '</option>');
34
+ tagMap[tag.id] = {
35
+ name: tag.name,
36
+ deviceName: device.name,
37
+ fullName: fullName
38
+ };
22
39
  });
23
40
  });
41
+
42
+ // Listen for tagSelected input changes
43
+ $('#node-input-tagSelected').on('change', function() {
44
+ var selectedValue = $(this).val();
45
+ // Parse format: tag.name(tag.id)
46
+ var match = selectedValue.match(/^(.+)\(([^)]+)\)$/);
47
+ if (match) {
48
+ var tagName = match[1];
49
+ var tagId = match[2];
50
+
51
+ // Set the actual stored fields
52
+ $('#node-input-tag').val(tagName);
53
+ $('#node-input-tagId').val(tagId);
54
+ }
55
+ });
56
+
57
+ // Initialize display (when editing existing node)
58
+ if (node.tagId && tagMap[node.tagId]) {
59
+ // Has tagId, construct tagSelected value
60
+ var tagName = node.tag || tagMap[node.tagId].name;
61
+ $('#node-input-tagSelected').val(tagName + '(' + node.tagId + ')');
62
+ } else if (node.tag && !node.tagId) {
63
+ // Old node: only has tag (tag.name), need to find corresponding tagId
64
+ // Note: if there are duplicate names, only the first match will be found
65
+ for (var tagId in tagMap) {
66
+ if (tagMap[tagId].name === node.tag) {
67
+ $('#node-input-tagSelected').val(node.tag + '(' + tagId + ')');
68
+ $('#node-input-tagId').val(tagId);
69
+ break;
70
+ }
71
+ }
72
+ }
24
73
  });
25
74
  }
26
75
  });
@@ -32,10 +81,12 @@
32
81
  <input type="text" id="node-input-name" placeholder="Name">
33
82
  </div>
34
83
  <div class="form-row">
35
- <label for="node-input-tag"><i class="fa fa-tag"></i> Tag</label>
36
- <input type="text" id="node-input-tag" list="fuxa-tags-set" placeholder="Tag Name">
84
+ <label for="node-input-tagSelected"><i class="fa fa-tag"></i> Tag</label>
85
+ <input type="text" id="node-input-tagSelected" list="fuxa-tags-set" placeholder="Select Tag">
37
86
  <datalist id="fuxa-tags-set"></datalist>
38
87
  </div>
88
+ <input type="hidden" id="node-input-tag">
89
+ <input type="hidden" id="node-input-tagId">
39
90
  </script>
40
91
 
41
92
  <script type="text/x-red" data-help-name="set-tag">
@@ -7,12 +7,18 @@ module.exports = function(RED) {
7
7
 
8
8
  this.on('input', async function(msg) {
9
9
  try {
10
- var tagId = fuxa.getTagId(config.tag, null);
10
+ // Prefer config.tagId, fallback to config.tag for backward compatibility
11
+ var tagId = config.tagId;
12
+ if (!tagId && config.tag) {
13
+ // Backward compatibility: old nodes use tag.name, need to convert to tagId
14
+ tagId = fuxa.getTagId(config.tag, null);
15
+ }
16
+
11
17
  if (tagId) {
12
18
  await fuxa.setTag(tagId, msg.payload);
13
19
  node.send(msg);
14
20
  } else {
15
- node.error('Tag not found: ' + config.tag, msg);
21
+ node.error('Tag not found: ' + (config.tag || config.tagId), msg);
16
22
  }
17
23
  } catch (err) {
18
24
  node.error(err, msg);
package/main.js CHANGED
@@ -148,6 +148,12 @@ try {
148
148
  if (mysettings.tokenExpiresIn) {
149
149
  settings.tokenExpiresIn = mysettings.tokenExpiresIn;
150
150
  }
151
+ if (!utils.isNullOrUndefined(mysettings.enableRefreshCookieAuth)) {
152
+ settings.enableRefreshCookieAuth = mysettings.enableRefreshCookieAuth;
153
+ }
154
+ if (mysettings.refreshTokenExpiresIn) {
155
+ settings.refreshTokenExpiresIn = mysettings.refreshTokenExpiresIn;
156
+ }
151
157
  if (mysettings.secretCode) {
152
158
  settings.secretCode = mysettings.secretCode;
153
159
  }
@@ -189,6 +195,12 @@ try {
189
195
  logger.error('Error loading user settings file: ' + userSettingsFile)
190
196
  }
191
197
 
198
+ // Ensure secure mode never runs with an empty/static-known JWT secret.
199
+ if (settings.secureEnabled && !settings.secretCode) {
200
+ settings.secretCode = utils.generateSecretCode();
201
+ logger.warn('Generated a random JWT secret in memory because secureEnabled=true and secretCode was missing. Persist it in settings for stable sessions across restarts.');
202
+ }
203
+
192
204
  // Check logger
193
205
  if (!settings.logDir) {
194
206
  settings.logDir = path.resolve(rootDir, '_logs');
@@ -260,6 +272,7 @@ var www = path.resolve(__dirname, '../client/dist');
260
272
  if (!fs.existsSync(www)) { // compatibility with docker/npm/electron
261
273
  www = path.resolve(__dirname, './dist');
262
274
  }
275
+
263
276
  settings.httpStatic = settings.httpStatic || www;
264
277
 
265
278
  if (parsedArgs.port !== undefined) {
@@ -321,10 +334,13 @@ const allowCrossDomain = function (req, res, next) {
321
334
 
322
335
  if (isOriginAllowed(origin)) {
323
336
  res.header('Access-Control-Allow-Origin', origin || '*');
337
+ if (settings.enableRefreshCookieAuth) {
338
+ res.header('Access-Control-Allow-Credentials', 'true');
339
+ }
324
340
  }
325
341
 
326
342
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
327
- res.header('Access-Control-Allow-Headers', 'x-access-token, x-auth-user, Origin, Content-Type, Accept');
343
+ res.header('Access-Control-Allow-Headers', 'x-access-token, x-auth-user, Origin, Content-Type, Accept, Skip-Auth, Skip-Error');
328
344
 
329
345
 
330
346
  if (req.method === 'OPTIONS') {
@@ -348,22 +364,24 @@ app.use('/_widgets', express.static(settings.widgetsFileDir));
348
364
  app.use('/snapshots', express.static(settings.webcamSnapShotsDir))
349
365
 
350
366
  var accessLogStream = fs.createWriteStream(settings.logDir + '/api.log', { flags: 'a' });
351
- app.use(morgan('combined', {
352
- stream: accessLogStream,
353
- skip: function (req, res) { return res.statusCode < 400 }
354
- }));
355
-
356
- app.use(morgan('dev', {
357
- skip: function (req, res) {
358
- return res.statusCode < 400
359
- }, stream: process.stderr
360
- }));
361
-
362
- app.use(morgan('dev', {
363
- skip: function (req, res) {
364
- return res.statusCode >= 400
365
- }, stream: process.stdout
366
- }));
367
+ if (runtime.settings.logApiLevel !== 'none') {
368
+ app.use(morgan('combined', {
369
+ stream: accessLogStream,
370
+ skip: function (req, res) { return res.statusCode < 400 }
371
+ }));
372
+
373
+ app.use(morgan('dev', {
374
+ skip: function (req, res) {
375
+ return res.statusCode < 400
376
+ }, stream: process.stderr
377
+ }));
378
+
379
+ app.use(morgan('dev', {
380
+ skip: function (req, res) {
381
+ return res.statusCode >= 400
382
+ }, stream: process.stdout
383
+ }));
384
+ }
367
385
 
368
386
  function mountSwaggerIfEnabled() {
369
387
  const swaggerEnabled = settings.swagger || settings.swaggerEnabled;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frangoteam/fuxa-min",
3
- "version": "1.2.11",
3
+ "version": "1.3.0",
4
4
  "description": "Web-based Process Visualization (SCADA/HMI/Dashboard) software",
5
5
  "main": "main.js",
6
6
  "scripts": {
@@ -36,12 +36,13 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@influxdata/influxdb-client": "1.25.0",
39
+ "@questdb/nodejs-client": "3.0.0",
39
40
  "@tdengine/rest": "3.0.2",
40
41
  "ads-client": "2.1.0",
41
42
  "app-root-path": "2.2.1",
42
43
  "async": "3.2.3",
43
44
  "async-mutex": "0.5.0",
44
- "axios": "0.30.2",
45
+ "axios": "1.13.5",
45
46
  "bcryptjs": "2.4.3",
46
47
  "bluebird": "3.7.2",
47
48
  "body-parser": "1.20.3",
@@ -52,19 +53,20 @@
52
53
  "fontkit": "^2.0.2",
53
54
  "fs-extra": "7.0.1",
54
55
  "influx": "5.9.3",
55
- "ip": "2.0.1",
56
+ "ip": "~2.0.1",
56
57
  "jsonwebtoken": "9.0.0",
57
58
  "live-plugin-manager": "0.15.1",
58
59
  "modbus-serial": "8.0.19",
59
- "morgan": "1.10.0",
60
+ "morgan": "1.10.1",
60
61
  "mqtt": "4.3.7",
61
62
  "node-bacnet": "0.2.4",
62
63
  "node-opcua": "2.149.0",
63
64
  "node-red": "^4.1.0",
64
65
  "node-schedule": "2.1.1",
65
- "nodemailer": "7.0.7",
66
+ "nodemailer": "7.0.13",
66
67
  "nopt": "5.0.0",
67
68
  "pdfmake": "0.2.5",
69
+ "pg": "8.18.0",
68
70
  "socket.io": "4.8.1",
69
71
  "sqlite3": "5.1.5",
70
72
  "swagger-ui-express": "^5.0.1",
@@ -72,6 +74,9 @@
72
74
  "ws": "8.18.0",
73
75
  "yamljs": "^0.3.0"
74
76
  },
77
+ "overrides": {
78
+ "tar": "^7.4.3"
79
+ },
75
80
  "devDependencies": {
76
81
  "@mapbox/node-pre-gyp": "^1.0.0",
77
82
  "@types/express": "5.0.0",
@@ -26,7 +26,7 @@ function ADSclient(_data, _logger, _events, _runtime) {
26
26
  * initialize the device type
27
27
  */
28
28
  this.init = function (_type) {
29
- console.error('Not supported!');
29
+ console.error('Not supported! (adsclient.init)');
30
30
  }
31
31
 
32
32
  /**
@@ -28,7 +28,7 @@ function EthernetIPclient(_data, _logger, _events, _runtime) {
28
28
  * initialize the device type
29
29
  */
30
30
  this.init = function (_type) {
31
- console.error('Not supported!');
31
+ console.error('Not supported! (ethernetip.init)');
32
32
  }
33
33
 
34
34
  /**
@@ -198,7 +198,7 @@ function GpioClient(_data, _logger, _events, _runtime) {
198
198
  */
199
199
  this.lastReadTimestamp = () => {
200
200
  return lastTimestampValue;
201
- console.error('Not supported!');
201
+ console.error('Not supported! (gpio.lastReadTimestamp)');
202
202
  }
203
203
 
204
204
  /**
@@ -24,7 +24,7 @@ function ODBCclient(_data, _logger, _events) {
24
24
  * initialize the device type
25
25
  */
26
26
  this.init = function (_type) {
27
- console.error('Not supported!');
27
+ console.error('Not supported! (odbc.init)');
28
28
  }
29
29
 
30
30
  /**
@@ -165,14 +165,14 @@ function ODBCclient(_data, _logger, _events) {
165
165
  * Return Tags values array { id: <name>, value: <value> }
166
166
  */
167
167
  this.getValues = function () {
168
- console.error('Not supported!');
168
+ console.error('Not supported! (odbc.getValues)');
169
169
  }
170
170
 
171
171
  /**
172
172
  * Return Tag value { id: <name>, value: <value>, ts: <lastTimestampValue> }
173
173
  */
174
174
  this.getValue = function (tagid) {
175
- console.error('Not supported!');
175
+ console.error(`Not supported! (odbc.getValue) (TagID: ${tagid})`);
176
176
  }
177
177
 
178
178
  /**
@@ -186,14 +186,14 @@ function ODBCclient(_data, _logger, _events) {
186
186
  * Return Tag property to show in frontend
187
187
  */
188
188
  this.getTagProperty = function (tagid) {
189
- console.error('Not supported!');
189
+ console.error(`Not supported! (odbc.getTagProperty) (TagID: ${tagid})`);
190
190
  }
191
191
 
192
192
  /**
193
193
  * Set the Tag value to device
194
194
  */
195
195
  this.setValue = function (tagid, value) {
196
- console.error('Not supported!');
196
+ console.error(`Not supported! (odbc.setValue) (TagID: ${tagid}, Value: ${value})`);
197
197
  }
198
198
 
199
199
  /**
@@ -14,7 +14,7 @@ function DeviceTemplate(_data, _logger, _events) {
14
14
  * initialize the device type
15
15
  */
16
16
  this.init = function (_type) {
17
- console.error('Not supported!');
17
+ console.error('Not supported! (template.init)');
18
18
  }
19
19
 
20
20
  /**
@@ -22,7 +22,7 @@ function DeviceTemplate(_data, _logger, _events) {
22
22
  * Emit connection status to clients, clear all Tags values
23
23
  */
24
24
  this.connect = function () {
25
- console.error('Not supported!');
25
+ console.error('Not supported! (template.connect)');
26
26
  // events.emit('device-status:changed', { id: data.id, status: 'connect-ok' });
27
27
  // events.emit('device-status:changed', { id: data.id, status: 'connect-error' });
28
28
  }
@@ -33,7 +33,7 @@ function DeviceTemplate(_data, _logger, _events) {
33
33
  * Emit connection status to clients, clear all Tags values
34
34
  */
35
35
  this.disconnect = function () {
36
- console.error('Not supported!');
36
+ console.error('Not supported! (template.disconnect)');
37
37
  // events.emit('device-status:changed', { id: data.id, status: 'connect-off' });
38
38
  }
39
39
 
@@ -42,7 +42,7 @@ function DeviceTemplate(_data, _logger, _events) {
42
42
  * Update the tags values list, save in DAQ if value changed or in interval and emit values to clients
43
43
  */
44
44
  this.polling = async function () {
45
- console.error('Not supported!');
45
+ console.error('Not supported! (template.polling)');
46
46
  // events.emit('device-value:changed', { id: data.name, values: values });
47
47
  }
48
48
 
@@ -50,49 +50,49 @@ function DeviceTemplate(_data, _logger, _events) {
50
50
  * Load Tags attribute to read with polling
51
51
  */
52
52
  this.load = function (_data) {
53
- console.error('Not supported!');
53
+ console.error(`Not supported! (template.load) (Data: ${_data})`);
54
54
  }
55
55
 
56
56
  /**
57
57
  * Return Tags values array { id: <name>, value: <value> }
58
58
  */
59
59
  this.getValues = function () {
60
- console.error('Not supported!');
60
+ console.error('Not supported! (template.getValues)');
61
61
  }
62
62
 
63
63
  /**
64
64
  * Return Tag value { id: <name>, value: <value>, ts: <lastTimestampValue> }
65
65
  */
66
66
  this.getValue = function (tagid) {
67
- console.error('Not supported!');
67
+ console.error(`Not supported! (template.getValue) (TagID: ${tagid})`);
68
68
  }
69
69
 
70
70
  /**
71
71
  * Return connection status 'connect-off', 'connect-ok', 'connect-error', 'connect-busy'
72
72
  */
73
73
  this.getStatus = function () {
74
- console.error('Not supported!');
74
+ console.error('Not supported! (template.getStatus)');
75
75
  }
76
76
 
77
77
  /**
78
78
  * Return Tag property to show in frontend
79
79
  */
80
80
  this.getTagProperty = function (tagid) {
81
- console.error('Not supported!');
81
+ console.error(`Not supported! (template.getTagProperty) (TagID: ${tagid})`);
82
82
  }
83
83
 
84
84
  /**
85
85
  * Set the Tag value to device
86
86
  */
87
87
  this.setValue = function (tagid, value) {
88
- console.error('Not supported!');
88
+ console.error(`Not supported! (template.setValue) (TagID: ${tagid}, Value: ${value})`);
89
89
  }
90
90
 
91
91
  /**
92
92
  * Return if device is connected
93
93
  */
94
94
  this.isConnected = function () {
95
- console.error('Not supported!');
95
+ console.error('Not supported! (template.isConnected)');
96
96
  }
97
97
 
98
98
  /**
@@ -107,7 +107,7 @@ function DeviceTemplate(_data, _logger, _events) {
107
107
  * @returns
108
108
  */
109
109
  this.lastReadTimestamp = () => {
110
- console.error('Not supported!');
110
+ console.error('Not supported! (template.lastReadTimestamp)');
111
111
  }
112
112
 
113
113
  /**
@@ -115,7 +115,7 @@ function DeviceTemplate(_data, _logger, _events) {
115
115
  * @returns
116
116
  */
117
117
  this.getTagDaqSettings = (tagId) => {
118
- console.error('Not supported!');
118
+ console.error(`Not supported! (template.getTagDaqSettings) (TagID: ${tagId})`);
119
119
  }
120
120
 
121
121
  /**
@@ -123,7 +123,7 @@ function DeviceTemplate(_data, _logger, _events) {
123
123
  * @returns
124
124
  */
125
125
  this.setTagDaqSettings = (tagId, settings) => {
126
- console.error('Not supported!');
126
+ console.error(`Not supported! (template.setTagDaqSettings) (TagID: ${tagId}, Settings: ${settings})`);
127
127
  }
128
128
  }
129
129
 
@@ -21,6 +21,7 @@ var logger;
21
21
  var daqDB = {}; // list of daqDB node: SQlite one pro device, influxDB only one
22
22
  var currentStorateDB;
23
23
  var runtime;
24
+ var questDbModule = null;
24
25
 
25
26
  function init(_settings, _log, _runtime) {
26
27
  settings = _settings;
@@ -42,7 +43,7 @@ function reset() {
42
43
  function addDaqNode(_id, fncgetprop) {
43
44
  var id = _id;
44
45
  const dbType = _getDbType();
45
- if (dbType === DaqStoreTypeEnum.influxDB || dbType === DaqStoreTypeEnum.influxDB18 || dbType === DaqStoreTypeEnum.TDengine) {
46
+ if (dbType === DaqStoreTypeEnum.influxDB || dbType === DaqStoreTypeEnum.influxDB18 || dbType === DaqStoreTypeEnum.TDengine || dbType === DaqStoreTypeEnum.questDB) {
46
47
  id = dbType;
47
48
  }
48
49
  if (!daqDB[id]) {
@@ -50,6 +51,14 @@ function addDaqNode(_id, fncgetprop) {
50
51
  daqDB[id] = InfluxDB.create(settings, logger, currentStorateDB);
51
52
  } else if(id === DaqStoreTypeEnum.TDengine){
52
53
  daqDB[id] = TDengine.create(settings, logger, currentStorateDB);
54
+ } else if(id === DaqStoreTypeEnum.questDB){
55
+ const QuestDB = _getQuestDbModule();
56
+ if (QuestDB) {
57
+ daqDB[id] = QuestDB.create(settings, logger, currentStorateDB);
58
+ } else {
59
+ logger.warn('daqstorage: QuestDB storage selected but package dependencies are not installed. Falling back to SQLite.');
60
+ daqDB[id] = SqliteDB.create(settings, logger, id, currentStorateDB);
61
+ }
53
62
  } else {
54
63
  daqDB[id] = SqliteDB.create(settings, logger, id, currentStorateDB);
55
64
  }
@@ -160,16 +169,33 @@ function _getDaqNode(tagid) {
160
169
 
161
170
  function _getDbType() {
162
171
  if (settings.daqstore && settings.daqstore.type) {
172
+ if (settings.daqstore.type === 'QuestDB') {
173
+ return DaqStoreTypeEnum.questDB;
174
+ }
163
175
  return settings.daqstore.type;
164
176
  }
165
177
  return DaqStoreTypeEnum.SQlite;
166
178
  }
167
179
 
180
+ function _getQuestDbModule() {
181
+ if (questDbModule) {
182
+ return questDbModule;
183
+ }
184
+ try {
185
+ questDbModule = require("./questdb");
186
+ } catch (err) {
187
+ questDbModule = null;
188
+ logger.warn(`daqstorage: QuestDB module unavailable (${err.message})`);
189
+ }
190
+ return questDbModule;
191
+ }
192
+
168
193
  var DaqStoreTypeEnum = {
169
194
  SQlite: 'SQlite',
170
195
  influxDB: 'influxDB',
171
196
  influxDB18: 'influxDB18',
172
197
  TDengine: 'TDengine',
198
+ questDB: 'questDB',
173
199
  }
174
200
 
175
201
  function _getValue(value) {
@@ -187,4 +213,4 @@ module.exports = {
187
213
  getNodesValues: getNodesValues,
188
214
  checkRetention: checkRetention,
189
215
  getCurrentStorageFnc: getCurrentStorageFnc,
190
- };
216
+ };