vrack2-core 0.0.1 → 1.0.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 (148) hide show
  1. package/README.md +25 -4
  2. package/docs/Bootstrap.md +77 -0
  3. package/docs/Container.md +124 -0
  4. package/docs/Device.md +272 -0
  5. package/docs/FastStart.md +111 -0
  6. package/docs/Structure.md +148 -0
  7. package/lib/Bootstrap.d.ts +79 -0
  8. package/lib/Bootstrap.js +103 -0
  9. package/lib/Container.d.ts +202 -6
  10. package/lib/Container.js +295 -27
  11. package/lib/IServiceStructure.d.ts +8 -0
  12. package/lib/IStructureDevice.d.ts +5 -0
  13. package/lib/ImportManager.d.ts +85 -3
  14. package/lib/ImportManager.js +122 -16
  15. package/lib/MainProcess.d.ts +30 -3
  16. package/lib/MainProcess.js +28 -6
  17. package/lib/Utility.d.ts +15 -21
  18. package/lib/Utility.js +40 -40
  19. package/lib/actions/Action.d.ts +10 -0
  20. package/lib/actions/Action.js +10 -0
  21. package/lib/actions/BasicAction.d.ts +60 -0
  22. package/lib/actions/BasicAction.js +62 -0
  23. package/lib/actions/GlobalAction.d.ts +5 -0
  24. package/lib/actions/GlobalAction.js +5 -0
  25. package/lib/actions/IAction.d.ts +7 -0
  26. package/lib/actions/ILocalAction.d.ts +7 -0
  27. package/lib/boot/BootClass.d.ts +93 -0
  28. package/lib/boot/BootClass.js +101 -0
  29. package/lib/boot/DeviceFileStorage.d.ts +38 -0
  30. package/lib/boot/DeviceFileStorage.js +112 -0
  31. package/lib/boot/DeviceManager.d.ts +190 -0
  32. package/lib/boot/DeviceManager.js +306 -0
  33. package/lib/boot/DeviceMetrics.d.ts +82 -0
  34. package/lib/boot/DeviceMetrics.js +128 -0
  35. package/lib/boot/StructureStorage.d.ts +59 -0
  36. package/lib/boot/StructureStorage.js +125 -0
  37. package/lib/errors/CoreError.d.ts +42 -25
  38. package/lib/errors/CoreError.js +44 -24
  39. package/lib/errors/ErrorManager.d.ts +18 -20
  40. package/lib/errors/ErrorManager.js +23 -22
  41. package/lib/index.d.ts +20 -4
  42. package/lib/index.js +28 -4
  43. package/lib/metrics/BasicMetric.d.ts +49 -0
  44. package/lib/metrics/BasicMetric.js +79 -0
  45. package/lib/metrics/IMetricSettings.d.ts +32 -0
  46. package/lib/metrics/IMetricSettings.js +2 -0
  47. package/lib/metrics/IvMs.d.ts +9 -0
  48. package/lib/metrics/IvMs.js +22 -0
  49. package/lib/metrics/IvS.d.ts +9 -0
  50. package/lib/metrics/IvS.js +22 -0
  51. package/lib/metrics/IvUs.d.ts +9 -0
  52. package/lib/metrics/IvUs.js +22 -0
  53. package/lib/metrics/Metric.d.ts +17 -0
  54. package/lib/metrics/Metric.js +27 -0
  55. package/lib/ports/BasicPort.d.ts +39 -0
  56. package/lib/ports/BasicPort.js +39 -0
  57. package/lib/ports/ILocalPort.d.ts +7 -0
  58. package/lib/ports/IPort.d.ts +7 -0
  59. package/lib/ports/Port.d.ts +10 -0
  60. package/lib/ports/Port.js +10 -0
  61. package/lib/ports/ReturnPort.d.ts +5 -0
  62. package/lib/ports/ReturnPort.js +5 -0
  63. package/lib/service/Device.d.ts +213 -78
  64. package/lib/service/Device.js +185 -83
  65. package/lib/service/DeviceConnect.d.ts +4 -8
  66. package/lib/service/DeviceConnect.js +4 -8
  67. package/lib/service/DevicePort.d.ts +15 -6
  68. package/lib/service/DevicePort.js +29 -12
  69. package/lib/service/IDeviceEvent.d.ts +4 -1
  70. package/lib/validator/IValidationProblem.d.ts +7 -0
  71. package/lib/validator/IValidationRule.d.ts +12 -0
  72. package/lib/validator/IValidationSubrule.d.ts +2 -0
  73. package/lib/validator/Rule.d.ts +6 -2
  74. package/lib/validator/Rule.js +12 -2
  75. package/lib/validator/Validator.d.ts +48 -3
  76. package/lib/validator/Validator.js +70 -18
  77. package/lib/validator/types/AnyType.d.ts +17 -0
  78. package/lib/validator/types/AnyType.js +34 -0
  79. package/lib/validator/types/ArrayType.d.ts +37 -4
  80. package/lib/validator/types/ArrayType.js +42 -6
  81. package/lib/validator/types/BasicType.d.ts +67 -7
  82. package/lib/validator/types/BasicType.js +74 -8
  83. package/lib/validator/types/BooleanType.d.ts +23 -0
  84. package/lib/validator/types/BooleanType.js +47 -0
  85. package/lib/validator/types/FunctionType.d.ts +17 -0
  86. package/lib/validator/types/FunctionType.js +38 -0
  87. package/lib/validator/types/NumberType.d.ts +40 -5
  88. package/lib/validator/types/NumberType.js +53 -14
  89. package/lib/validator/types/ObjectType.d.ts +32 -5
  90. package/lib/validator/types/ObjectType.js +42 -8
  91. package/lib/validator/types/StringType.d.ts +30 -5
  92. package/lib/validator/types/StringType.js +33 -7
  93. package/package.json +10 -9
  94. package/src/Bootstrap.ts +122 -0
  95. package/src/Container.ts +411 -43
  96. package/src/IServiceStructure.ts +9 -0
  97. package/src/IStructureDevice.ts +5 -0
  98. package/src/ImportManager.ts +119 -11
  99. package/src/MainProcess.ts +53 -8
  100. package/src/Utility.ts +35 -36
  101. package/src/actions/Action.ts +12 -0
  102. package/src/actions/BasicAction.ts +63 -0
  103. package/src/actions/GlobalAction.ts +5 -0
  104. package/src/actions/IAction.ts +7 -0
  105. package/src/actions/ILocalAction.ts +7 -0
  106. package/src/boot/BootClass.ts +117 -0
  107. package/src/boot/DeviceFileStorage.ts +96 -0
  108. package/src/boot/DeviceManager.ts +339 -0
  109. package/src/boot/DeviceMetrics.ts +129 -0
  110. package/src/boot/StructureStorage.ts +108 -0
  111. package/src/errors/CoreError.ts +52 -26
  112. package/src/errors/ErrorManager.ts +46 -33
  113. package/src/index.ts +30 -6
  114. package/src/metrics/BasicMetric.ts +84 -0
  115. package/src/metrics/IMetricSettings.ts +38 -0
  116. package/src/metrics/IvMs.ts +18 -0
  117. package/src/metrics/IvS.ts +18 -0
  118. package/src/metrics/IvUs.ts +17 -0
  119. package/src/metrics/Metric.ts +25 -0
  120. package/src/ports/BasicPort.ts +39 -0
  121. package/src/ports/ILocalPort.ts +7 -0
  122. package/src/ports/IPort.ts +7 -0
  123. package/src/ports/Port.ts +11 -1
  124. package/src/ports/ReturnPort.ts +5 -0
  125. package/src/service/Device.ts +234 -103
  126. package/src/service/DeviceConnect.ts +4 -8
  127. package/src/service/DevicePort.ts +30 -11
  128. package/src/service/IDeviceEvent.ts +4 -1
  129. package/src/validator/IValidationProblem.ts +7 -0
  130. package/src/validator/IValidationRule.ts +12 -0
  131. package/src/validator/IValidationSubrule.ts +3 -0
  132. package/src/validator/Rule.ts +16 -2
  133. package/src/validator/Validator.ts +74 -23
  134. package/src/validator/types/AnyType.ts +32 -0
  135. package/src/validator/types/ArrayType.ts +43 -7
  136. package/src/validator/types/BasicType.ts +78 -9
  137. package/src/validator/types/BooleanType.ts +49 -0
  138. package/src/validator/types/FunctionType.ts +39 -0
  139. package/src/validator/types/NumberType.ts +53 -15
  140. package/src/validator/types/ObjectType.ts +52 -14
  141. package/src/validator/types/StringType.ts +34 -10
  142. package/docs/RU-README.md +0 -6
  143. package/lib/DeviceManager.d.ts +0 -32
  144. package/lib/DeviceManager.js +0 -143
  145. package/lib/test.d.ts +0 -1
  146. package/lib/test.js +0 -58
  147. package/src/DeviceManager.ts +0 -124
  148. package/src/test.ts +0 -82
@@ -0,0 +1,306 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ const path_1 = __importDefault(require("path"));
39
+ const fs_1 = __importDefault(require("fs"));
40
+ const ErrorManager_1 = __importDefault(require("../errors/ErrorManager"));
41
+ const Rule_1 = __importDefault(require("../validator/Rule"));
42
+ const CoreError_1 = __importDefault(require("../errors/CoreError"));
43
+ const BootClass_1 = __importDefault(require("./BootClass"));
44
+ const ImportManager_1 = __importDefault(require("../ImportManager"));
45
+ ErrorManager_1.default.register('DeviceManager', 'S5dBTBKTnVbF', 'DM_DEVICE_NOT_FOUND', 'Device not found', {
46
+ device: Rule_1.default.string().require().example('Master').description('Device name')
47
+ });
48
+ ErrorManager_1.default.register('DeviceManager', '2CJSDE95V9O1', 'DM_LIST_NOT_FOUND', 'list.json not found', {
49
+ vendor: Rule_1.default.string().require().example('vrack').description('Device group name')
50
+ });
51
+ ErrorManager_1.default.register('DeviceManager', 'BPX96F93ZCJA', 'DM_LIST_INCORRECT', 'list.json is not correct', {
52
+ vendor: Rule_1.default.string().require().example('vrack').description('Device group name')
53
+ });
54
+ ErrorManager_1.default.register('DeviceManager', 'H1NDNVCOLWST', 'DM_VENDOR_NOT_FOUND', 'Vendor not found', {
55
+ vendor: Rule_1.default.string().require().example('vrack').description('Vendor name')
56
+ });
57
+ ErrorManager_1.default.register('DeviceManager', 'HQ62LW1YLTDE', 'DM_GET_INFO_EXCEPTION', 'Error retrieving device data, see error in attachment', {});
58
+ /**
59
+ * BootClass which generates a list of available devices for the container.
60
+ * Provides the ability to initialize devices and provide information about them
61
+ *
62
+ *
63
+ * @see get
64
+ */
65
+ class DeviceManager extends BootClass_1.default {
66
+ constructor() {
67
+ super(...arguments);
68
+ /**
69
+ * Contains a list of devices and their full path to the class
70
+ * Like a:
71
+ *
72
+ * ```js
73
+ * {
74
+ * "vendorname.Devicename": '/path/to/js/file.js'
75
+ * }
76
+ * ```
77
+ * */
78
+ this.devices = new Map();
79
+ /**
80
+ * Vendor array.
81
+ *
82
+ * @see IDeviceVendor
83
+ */
84
+ this.vendorList = [];
85
+ }
86
+ checkOptions() {
87
+ return {
88
+ dir: Rule_1.default.string().require().default('./devices'),
89
+ systemDir: Rule_1.default.string().require().default(ImportManager_1.default.systemPath()),
90
+ };
91
+ }
92
+ process() {
93
+ this.updateDeviceList();
94
+ }
95
+ /**
96
+ * Return vendor list
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * ['vrack', 'basic', 'net']
101
+ * ```
102
+ */
103
+ getVendorList() {
104
+ const result = [];
105
+ for (const dgroup of this.vendorList)
106
+ result.push(dgroup.name);
107
+ return result;
108
+ }
109
+ /**
110
+ * Returns a list of devices from a specific vendor
111
+ *
112
+ * @param vendor Vendor name
113
+ * @see getVendorList()
114
+ */
115
+ getVendorDeviceList(vendor) {
116
+ const vgroup = this.findVendor(vendor);
117
+ if (typeof vgroup === "boolean")
118
+ throw ErrorManager_1.default.make('DM_VENDOR_NOT_FOUND', { vendor }).setTrace(new Error());
119
+ return vgroup.deviceList;
120
+ }
121
+ /**
122
+ * Exports all basic device parameters and collects them in one object
123
+ * Used to generate documentation for the device
124
+ *
125
+ * @see IDeivceInfo
126
+ */
127
+ getDeviceInfo(vendor, device) {
128
+ return __awaiter(this, void 0, void 0, function* () {
129
+ const di = [vendor, device].join('.');
130
+ const DeviceClass = yield this.get(di);
131
+ const dev = new DeviceClass('1', di, this);
132
+ const result = { actions: {}, metrics: {}, inputs: {}, outputs: {}, options: {}, description: '' };
133
+ try {
134
+ const preOptions = dev.checkOptions();
135
+ for (const oName in preOptions)
136
+ result.options[oName] = preOptions[oName].export();
137
+ const dInputs = dev.inputs();
138
+ for (const iName in dInputs)
139
+ result.inputs[iName] = dInputs[iName].export();
140
+ const dOutputs = dev.outputs();
141
+ for (const oName in dOutputs)
142
+ result.outputs[oName] = dOutputs[oName].export();
143
+ const dActions = dev.actions();
144
+ for (const aName in dActions)
145
+ result.actions[aName] = dActions[aName].export();
146
+ const dMetrics = dev.metrics();
147
+ for (const mName in dMetrics)
148
+ result.metrics[mName] = dMetrics[mName].export();
149
+ result.description = dev.description();
150
+ }
151
+ catch (error) {
152
+ throw ErrorManager_1.default.make('DM_GET_INFO_EXCEPTION').setTrace(new Error).add(error);
153
+ }
154
+ return result;
155
+ });
156
+ }
157
+ /**
158
+ * Method for updating the device list
159
+ * Updates the available device lists.
160
+ *
161
+ * Searches the directory specified in `options.dir` and adds all directories in it as vendors.
162
+ * Each folder attempts to read the list.json file to get a list of vendor devices
163
+ *
164
+ * Two types of list.json file definition are supported
165
+ *
166
+ * First type - array:
167
+ *
168
+ * ```json
169
+ * ['Device1', 'Device2', 'Device3']
170
+ * ```
171
+ * Second type - Object
172
+ * This approach allows you to point to devices that are deeper than the vendor's root folder
173
+ *
174
+ * ```json
175
+ * {
176
+ * "Master": "devices/Master",
177
+ * "Interval": "devices/Interval",
178
+ * "Guard": "devices/Guard",
179
+ * }
180
+ * ```
181
+ *
182
+ * @see arrayDeviceListPrepare()
183
+ * @see objectDeviceListPrepare()
184
+ */
185
+ updateDeviceList() {
186
+ this.vendorList = [];
187
+ this.devices.clear();
188
+ const dirs = ImportManager_1.default.dirList(path_1.default.join(this.options.systemDir, this.options.dir)).sort();
189
+ for (const vendor of dirs) {
190
+ const group = {
191
+ name: vendor,
192
+ dir: this.options.dir,
193
+ deviceList: [],
194
+ errors: [],
195
+ description: ''
196
+ };
197
+ this.vendorList.push(group);
198
+ const listPath = path_1.default.join(this.options.systemDir, this.options.dir, vendor, 'list.json');
199
+ if (!fs_1.default.existsSync(listPath)) {
200
+ group.errors.push(ErrorManager_1.default.make('DM_LIST_NOT_FOUND', { vendor }).setTrace(new Error));
201
+ continue;
202
+ }
203
+ try {
204
+ const list = JSON.parse(fs_1.default.readFileSync(listPath).toString('utf-8'));
205
+ if (Array.isArray(list)) { // if device list like a [ 'DeviceName', 'DeviceTwo' ]
206
+ group.deviceList = this.arrayDeviceListPrepare(list, group);
207
+ }
208
+ else if (typeof list === "object") { // if device list lie a { DeviceID?: 'PathToDevice' }
209
+ group.deviceList = this.objectDeviceListPrepare(list, group);
210
+ }
211
+ else
212
+ throw new Error();
213
+ }
214
+ catch (err) {
215
+ if (err instanceof CoreError_1.default)
216
+ group.errors.push(err);
217
+ else
218
+ group.errors.push(ErrorManager_1.default.make('DM_LIST_INCORRECT', { vendor }).setTrace(new Error));
219
+ }
220
+ }
221
+ }
222
+ /**
223
+ * Return class of device
224
+ *
225
+ * Requires special device string of path
226
+ * example "vrack.System" where "vrack" is vendor and "System" is device class
227
+ * @param {string} device Device path string
228
+ */
229
+ get(device, updateList = true) {
230
+ return __awaiter(this, void 0, void 0, function* () {
231
+ const p = this.devices.get(device); // return device path or undefined
232
+ if (typeof p === 'string') {
233
+ const deviceClass = yield Promise.resolve(`${p}`).then(s => __importStar(require(s))); // try import
234
+ if (deviceClass.default)
235
+ return deviceClass.default;
236
+ }
237
+ // Устройство не найдено, но не исключено что если перестроить дерево
238
+ // вендоров и устройств все будет так же
239
+ // По умолчанию мы попытаемся обновить дерево
240
+ if (updateList) {
241
+ yield this.updateDeviceList();
242
+ return yield this.get(device, false);
243
+ }
244
+ throw ErrorManager_1.default.make('DM_DEVICE_NOT_FOUND', { device });
245
+ });
246
+ }
247
+ /**
248
+ * Find vendor by name
249
+ *
250
+ * Not found if return boolean
251
+ */
252
+ findVendor(vendor) {
253
+ for (const dgroup of this.vendorList)
254
+ if (dgroup.name === vendor)
255
+ return dgroup;
256
+ return false;
257
+ }
258
+ /**
259
+ * Processes a list of devices as an Array
260
+ *
261
+ * Takes an Array of type
262
+ * ```
263
+ * ['DeviceName', 'DeviceName2']
264
+ * ```
265
+ * @return {Array<string>} Sorted list
266
+ */
267
+ arrayDeviceListPrepare(list, group) {
268
+ for (const name of list) {
269
+ const reqPath = path_1.default.join(this.options.systemDir, this.options.dir, group.name, name);
270
+ if (!fs_1.default.existsSync(reqPath + '.js')) {
271
+ group.errors.push(ErrorManager_1.default.make('DM_DEVICE_NOT_FOUND', { device: name }));
272
+ }
273
+ this.devices.set(group.name + '.' + name, reqPath);
274
+ }
275
+ list.sort();
276
+ return list;
277
+ }
278
+ /**
279
+ * Processes a list of devices as an object
280
+ *
281
+ * Takes an object of type
282
+ * ```
283
+ * {
284
+ * DeviceName: 'path/to/Device'
285
+ * }
286
+ * ```
287
+ *
288
+ * return keys of list
289
+ * ```
290
+ * ['DeviceName']
291
+ * ```
292
+ *
293
+ * Set in this.devices for device name requiere path
294
+ */
295
+ objectDeviceListPrepare(list, group) {
296
+ for (const name in list) {
297
+ const reqPath = path_1.default.join(this.options.systemDir, this.options.dir, group.name, list[name]);
298
+ if (!fs_1.default.existsSync(reqPath + '.js')) {
299
+ group.errors.push(ErrorManager_1.default.make('DM_DEVICE_NOT_FOUND', { device: name }).setTrace(new Error));
300
+ }
301
+ this.devices.set(group.name + '.' + name, reqPath);
302
+ }
303
+ return Object.keys(list).sort();
304
+ }
305
+ }
306
+ exports.default = DeviceManager;
@@ -0,0 +1,82 @@
1
+ import { Interval, SingleDB } from "vrack-db";
2
+ import IDeviceEvent from "../service/IDeviceEvent";
3
+ import BootClass from "./BootClass";
4
+ import IMetricSettings from "../metrics/IMetricSettings";
5
+ /**
6
+ * A class to support metrics inside devices
7
+ * Using a database vrack-db. Collects and stores container metrics
8
+ *
9
+ * @see SingleDB
10
+ *
11
+ * Uses the `device.metric` and `device.register.metric` events
12
+ *
13
+ * @see deviceMetric()
14
+ * @see deviceRegiterMetric()
15
+ */
16
+ export default class DeviceMetrics extends BootClass {
17
+ /**
18
+ * VRack-DB class instance
19
+ */
20
+ DB: SingleDB;
21
+ process(): void;
22
+ /**
23
+ * Checks if the metric exists in the device
24
+ *
25
+ * @param device Device ID
26
+ * @param name Registered metric name
27
+ */
28
+ has(device: string, name: string): boolean;
29
+ /**
30
+ * Read device metric from the database
31
+ *
32
+ * @param device Device ID
33
+ * @param name Registered metric name
34
+ * @param period Period in the format 'now-6h:now' @see SingleDB.read
35
+ * @param precision Accuracy interval '15m', '5s', '1h' or count of metrics 10, 200, 1500
36
+ * @param precision func Data aggregation function @see SingleDB.read
37
+ */
38
+ read(device: string, name: string, period: string, precision: string | number, func?: string): import("vrack-db").IMetricReadResult;
39
+ /**
40
+ * Registers the device metric
41
+ *
42
+ * When a device is initialized - the container gets a list of
43
+ * device metrics and passes them to the `device.register.metric` event for each metric.
44
+ *
45
+ * @param nEvent Object like a { device: 'Device ID', data: 'metric.name', trace: IMetricSettings object}
46
+ * @see IMetricSettings
47
+ * @see registerMetric
48
+ */
49
+ protected deviceRegiterMetric(nEvent: IDeviceEvent): void;
50
+ /**
51
+ * @see deviceRegiterMetric
52
+ * */
53
+ protected registerMetric(path: string, metric: IMetricSettings): void;
54
+ /**
55
+ * A method of writing a metric to a database.
56
+ *
57
+ * @param nEvent Object like a { device: 'Device ID', data: 'metric.name', trace: { value: metric value 123, modify: function of vrack db modify } }
58
+ * @example
59
+ * ```ts
60
+ * deviceMetric({
61
+ * device: 'Device ID',
62
+ * data: 'metric.name',
63
+ * trace: { value: 5.25, modify: 'last'}
64
+ * })
65
+ * ```
66
+ */
67
+ protected deviceMetric(nEvent: IDeviceEvent): void;
68
+ /**
69
+ * Selects the interval class depending on the specified minimal time unit
70
+ *
71
+ * @param interval s | ms | us
72
+ *
73
+ */
74
+ protected selectInterval(interval: string): typeof Interval;
75
+ /**
76
+ * Return metric path
77
+ *
78
+ * @param device Device ID
79
+ * @param name Metric name
80
+ */
81
+ protected getMetricPath(device: string, name: string): string;
82
+ }
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright © 2025 Boris Bobylev. All rights reserved.
4
+ * Licensed under the Apache License, Version 2.0
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ const vrack_db_1 = require("vrack-db");
11
+ const BootClass_1 = __importDefault(require("./BootClass"));
12
+ /**
13
+ * A class to support metrics inside devices
14
+ * Using a database vrack-db. Collects and stores container metrics
15
+ *
16
+ * @see SingleDB
17
+ *
18
+ * Uses the `device.metric` and `device.register.metric` events
19
+ *
20
+ * @see deviceMetric()
21
+ * @see deviceRegiterMetric()
22
+ */
23
+ class DeviceMetrics extends BootClass_1.default {
24
+ constructor() {
25
+ super(...arguments);
26
+ /**
27
+ * VRack-DB class instance
28
+ */
29
+ this.DB = new vrack_db_1.SingleDB();
30
+ }
31
+ process() {
32
+ this.Container.on('device.metric', this.deviceMetric.bind(this));
33
+ this.Container.on('device.register.metric', this.deviceRegiterMetric.bind(this));
34
+ }
35
+ /**
36
+ * Checks if the metric exists in the device
37
+ *
38
+ * @param device Device ID
39
+ * @param name Registered metric name
40
+ */
41
+ has(device, name) {
42
+ const path = this.getMetricPath(device, name);
43
+ if (!this.DB.has(path))
44
+ return false;
45
+ return true;
46
+ }
47
+ /**
48
+ * Read device metric from the database
49
+ *
50
+ * @param device Device ID
51
+ * @param name Registered metric name
52
+ * @param period Period in the format 'now-6h:now' @see SingleDB.read
53
+ * @param precision Accuracy interval '15m', '5s', '1h' or count of metrics 10, 200, 1500
54
+ * @param precision func Data aggregation function @see SingleDB.read
55
+ */
56
+ read(device, name, period, precision, func) {
57
+ const path = this.getMetricPath(device, name);
58
+ return this.DB.read(path, period, precision, func);
59
+ }
60
+ /**
61
+ * Registers the device metric
62
+ *
63
+ * When a device is initialized - the container gets a list of
64
+ * device metrics and passes them to the `device.register.metric` event for each metric.
65
+ *
66
+ * @param nEvent Object like a { device: 'Device ID', data: 'metric.name', trace: IMetricSettings object}
67
+ * @see IMetricSettings
68
+ * @see registerMetric
69
+ */
70
+ deviceRegiterMetric(nEvent) {
71
+ this.registerMetric(this.getMetricPath(nEvent.device, nEvent.data), nEvent.trace);
72
+ }
73
+ /**
74
+ * @see deviceRegiterMetric
75
+ * */
76
+ registerMetric(path, metric) {
77
+ this.DB.metric({
78
+ name: path,
79
+ retentions: metric.retentions,
80
+ tStorage: metric.tType,
81
+ vStorage: metric.vType,
82
+ CInterval: this.selectInterval(metric.interval)
83
+ });
84
+ }
85
+ /**
86
+ * A method of writing a metric to a database.
87
+ *
88
+ * @param nEvent Object like a { device: 'Device ID', data: 'metric.name', trace: { value: metric value 123, modify: function of vrack db modify } }
89
+ * @example
90
+ * ```ts
91
+ * deviceMetric({
92
+ * device: 'Device ID',
93
+ * data: 'metric.name',
94
+ * trace: { value: 5.25, modify: 'last'}
95
+ * })
96
+ * ```
97
+ */
98
+ deviceMetric(nEvent) {
99
+ const path = this.getMetricPath(nEvent.device, nEvent.data);
100
+ if (!this.DB.has(path))
101
+ return;
102
+ this.DB.write(path, nEvent.trace.value, 0, nEvent.trace.modify);
103
+ }
104
+ /**
105
+ * Selects the interval class depending on the specified minimal time unit
106
+ *
107
+ * @param interval s | ms | us
108
+ *
109
+ */
110
+ selectInterval(interval) {
111
+ switch (interval) {
112
+ case 's': return vrack_db_1.Interval;
113
+ case 'ms': return vrack_db_1.IntervalMs;
114
+ case 'us': return vrack_db_1.IntervalUs;
115
+ }
116
+ return vrack_db_1.Interval;
117
+ }
118
+ /**
119
+ * Return metric path
120
+ *
121
+ * @param device Device ID
122
+ * @param name Metric name
123
+ */
124
+ getMetricPath(device, name) {
125
+ return (device + '.' + name).toLowerCase();
126
+ }
127
+ }
128
+ exports.default = DeviceMetrics;
@@ -0,0 +1,59 @@
1
+ import BootClass from "./BootClass";
2
+ import BasicType from "../validator/types/BasicType";
3
+ import { IContainerStructure } from "../Container";
4
+ /**
5
+ * A boot class for storing the structure of a container.
6
+ *
7
+ * When a container is created, it is assigned a unique identifier.
8
+ * This identifier is used as parameters of methods.
9
+ *
10
+ * @see getById
11
+ * @see updateById
12
+ *
13
+ * When the container is loaded it calls “beforeLoaded”.
14
+ * At this point it updates the structure from disk to the structure
15
+ * of the container itself and writes the changes
16
+ *
17
+ * @see beforeLoadedUpdate
18
+ *
19
+ * */
20
+ export default class StructureStorage extends BootClass {
21
+ checkOptions(): {
22
+ [key: string]: BasicType;
23
+ };
24
+ process(): void;
25
+ /**
26
+ * Updates the structure on disk using the structure of
27
+ * the container itself when it is loaded
28
+ *
29
+ *
30
+ * @see StructureStorage.process
31
+ */
32
+ beforeLoadedUpdate(): Promise<void>;
33
+ /**
34
+ * Returns structure by container identifier
35
+ *
36
+ * @param id Container ID
37
+ */
38
+ getById(id: string): Promise<IContainerStructure>;
39
+ /**
40
+ * Updating the container structure
41
+ *
42
+ * @param id Container ID
43
+ * @param structure updated container structure object
44
+ */
45
+ updateById(id: string, structure: IContainerStructure): Promise<void>;
46
+ /**
47
+ * Updates the display structure parameter from the file structure
48
+ *
49
+ * @param cStruct now container structure
50
+ * @param structure new structure
51
+ */
52
+ protected updateStructure(cStruct: IContainerStructure, structure: IContainerStructure, id: string): void;
53
+ /**
54
+ * Forms the path to the structure file by its identifier
55
+ *
56
+ * @param id Container ID
57
+ */
58
+ protected makeFilePath(id: string): string;
59
+ }
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright © 2024 Boris Bobylev. All rights reserved.
4
+ * Licensed under the Apache License, Version 2.0
5
+ */
6
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
7
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
8
+ return new (P || (P = Promise))(function (resolve, reject) {
9
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
10
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
11
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
12
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
13
+ });
14
+ };
15
+ var __importDefault = (this && this.__importDefault) || function (mod) {
16
+ return (mod && mod.__esModule) ? mod : { "default": mod };
17
+ };
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ const BootClass_1 = __importDefault(require("./BootClass"));
20
+ const Rule_1 = __importDefault(require("../validator/Rule"));
21
+ const fs_1 = require("fs");
22
+ const path_1 = __importDefault(require("path"));
23
+ const ImportManager_1 = __importDefault(require("../ImportManager"));
24
+ const ErrorManager_1 = __importDefault(require("../errors/ErrorManager"));
25
+ ErrorManager_1.default.register('StructureStorage', 'FKb5raEUDFgU', 'SS_STRUCT_NOT_FOUND', 'Structure ID not found', {
26
+ id: Rule_1.default.string().require().example('vrack').description('Structure id')
27
+ });
28
+ /**
29
+ * A boot class for storing the structure of a container.
30
+ *
31
+ * When a container is created, it is assigned a unique identifier.
32
+ * This identifier is used as parameters of methods.
33
+ *
34
+ * @see getById
35
+ * @see updateById
36
+ *
37
+ * When the container is loaded it calls “beforeLoaded”.
38
+ * At this point it updates the structure from disk to the structure
39
+ * of the container itself and writes the changes
40
+ *
41
+ * @see beforeLoadedUpdate
42
+ *
43
+ * */
44
+ class StructureStorage extends BootClass_1.default {
45
+ checkOptions() {
46
+ return {
47
+ structureDir: Rule_1.default.string().require().default('./structure')
48
+ };
49
+ }
50
+ process() {
51
+ if (!(0, fs_1.existsSync)(this.options.structureDir))
52
+ (0, fs_1.mkdirSync)(this.options.structureDir, { recursive: true });
53
+ this.Container.on('beforeLoaded', this.beforeLoadedUpdate.bind(this));
54
+ }
55
+ /**
56
+ * Updates the structure on disk using the structure of
57
+ * the container itself when it is loaded
58
+ *
59
+ *
60
+ * @see StructureStorage.process
61
+ */
62
+ beforeLoadedUpdate() {
63
+ return __awaiter(this, void 0, void 0, function* () {
64
+ const fp = this.makeFilePath(this.Container.id);
65
+ let structure = {};
66
+ try {
67
+ if ((0, fs_1.existsSync)(fp))
68
+ structure = ImportManager_1.default.importJSON(fp);
69
+ const cStruct = yield this.Container.getStructure();
70
+ this.updateStructure(cStruct, structure, this.Container.id);
71
+ }
72
+ catch (error) {
73
+ this.error(error);
74
+ }
75
+ });
76
+ }
77
+ /**
78
+ * Returns structure by container identifier
79
+ *
80
+ * @param id Container ID
81
+ */
82
+ getById(id) {
83
+ return __awaiter(this, void 0, void 0, function* () {
84
+ const fp = this.makeFilePath(id);
85
+ if (!(0, fs_1.existsSync)(fp))
86
+ throw ErrorManager_1.default.make('SS_STRUCT_NOT_FOUND', { id });
87
+ return ImportManager_1.default.importJSON(fp);
88
+ });
89
+ }
90
+ /**
91
+ * Updating the container structure
92
+ *
93
+ * @param id Container ID
94
+ * @param structure updated container structure object
95
+ */
96
+ updateById(id, structure) {
97
+ return __awaiter(this, void 0, void 0, function* () {
98
+ const cStruct = yield this.getById(id);
99
+ this.updateStructure(cStruct, structure, id);
100
+ });
101
+ }
102
+ /**
103
+ * Updates the display structure parameter from the file structure
104
+ *
105
+ * @param cStruct now container structure
106
+ * @param structure new structure
107
+ */
108
+ updateStructure(cStruct, structure, id) {
109
+ for (const dID in cStruct) {
110
+ if (structure[dID] && structure[dID].display)
111
+ cStruct[dID].display = structure[dID].display;
112
+ }
113
+ const fp = this.makeFilePath(id);
114
+ (0, fs_1.writeFileSync)(fp, JSON.stringify(cStruct));
115
+ }
116
+ /**
117
+ * Forms the path to the structure file by its identifier
118
+ *
119
+ * @param id Container ID
120
+ */
121
+ makeFilePath(id) {
122
+ return path_1.default.join(this.options.structureDir, id + '.json');
123
+ }
124
+ }
125
+ exports.default = StructureStorage;