@tetherto/mdk-core 0.0.0 → 0.12.1

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 (54) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +572 -0
  3. package/index.js +519 -0
  4. package/lib/address-policy.js +124 -0
  5. package/lib/local-discovery.js +321 -0
  6. package/lib/services/actions.service.js +68 -0
  7. package/lib/services/alerts.service.js +207 -0
  8. package/lib/services/comments.service.js +118 -0
  9. package/lib/services/log-history.service.js +307 -0
  10. package/lib/services/logs.service.js +249 -0
  11. package/lib/services/pool-utils/constants.js +20 -0
  12. package/lib/services/pool-utils/time.js +49 -0
  13. package/lib/services/pool.service.js +397 -0
  14. package/lib/services/provisioning.service.js +420 -0
  15. package/lib/services/settings.service.js +26 -0
  16. package/lib/services/snaps.service.js +181 -0
  17. package/lib/services/stats.service.js +205 -0
  18. package/lib/stats/README.md +80 -0
  19. package/lib/stats/index.js +57 -0
  20. package/lib/stats/ops/alerts_aggr.js +40 -0
  21. package/lib/stats/ops/alerts_group_cnt.js +43 -0
  22. package/lib/stats/ops/arr_concat.js +27 -0
  23. package/lib/stats/ops/array_obj_calc.js +41 -0
  24. package/lib/stats/ops/avg.js +42 -0
  25. package/lib/stats/ops/cnt.js +19 -0
  26. package/lib/stats/ops/group.js +38 -0
  27. package/lib/stats/ops/group_avg.js +53 -0
  28. package/lib/stats/ops/group_cnt.js +38 -0
  29. package/lib/stats/ops/group_max.js +40 -0
  30. package/lib/stats/ops/group_multiple_stats.js +40 -0
  31. package/lib/stats/ops/group_sum.js +40 -0
  32. package/lib/stats/ops/index.js +35 -0
  33. package/lib/stats/ops/nested_obj_concat.js +54 -0
  34. package/lib/stats/ops/obj_concat.js +33 -0
  35. package/lib/stats/ops/sum.js +27 -0
  36. package/lib/stats/utils.js +99 -0
  37. package/lib/templates/alerts.js +128 -0
  38. package/lib/templates/stats.js +476 -0
  39. package/lib/things/constants.js +65 -0
  40. package/lib/things/container.js +84 -0
  41. package/lib/things/miner.js +190 -0
  42. package/lib/things/powermeter.js +30 -0
  43. package/lib/things/sensor.js +18 -0
  44. package/lib/things/thing.js +93 -0
  45. package/lib/utils.js +603 -0
  46. package/lib/worker-infra.js +221 -0
  47. package/package.json +64 -1
  48. package/services.js +246 -0
  49. package/utils/compose-yaml.js +56 -0
  50. package/utils/constants.js +30 -0
  51. package/utils/index.js +29 -0
  52. package/utils/initialize.js +148 -0
  53. package/utils/service-bootstrap.js +271 -0
  54. package/worker.js +9 -0
@@ -0,0 +1,476 @@
1
+ 'use strict'
2
+
3
+ const { groupBy } = require('../stats/utils')
4
+ const { hasErrorAndPositiveHashrate } = require('../utils')
5
+ const { STATUS, POWER_MODE, MAINTENANCE } = require('../things/constants')
6
+
7
+ // Base stat spec data per device family. Workers compose their own
8
+ // { conf, specs } template object from these — the exported objects are
9
+ // never mutated (see alerts.js for why).
10
+
11
+ const CONF = {
12
+ skipTagPrefixes: ['id-', 'code-']
13
+ }
14
+
15
+ const MINER_CONF = {
16
+ skipTagPrefixes: ['pos-', 'id-', 'code-', 'site-']
17
+ }
18
+
19
+ const DEFAULT_OPS = {
20
+ alerts_cnt: {
21
+ op: 'alerts_group_cnt',
22
+ src: 'last.alerts'
23
+ }
24
+ }
25
+
26
+ const MINER_DEFAULT_OPS = {
27
+ ...DEFAULT_OPS,
28
+ hashrate_mhs_1m_sum: {
29
+ op: 'sum',
30
+ src: 'last.snap.stats.hashrate_mhs.t_5m'
31
+ },
32
+ hashrate_mhs_1m_group_sum: {
33
+ op: 'group_sum',
34
+ src: 'last.snap.stats.hashrate_mhs.t_5m',
35
+ group: groupBy('info.container')
36
+ },
37
+ hashrate_mhs_1m_avg: {
38
+ op: 'avg',
39
+ src: 'last.snap.stats.hashrate_mhs.t_5m'
40
+ },
41
+ hashrate_mhs_1m_cnt: {
42
+ op: 'cnt',
43
+ src: 'last.snap.stats.hashrate_mhs.t_5m',
44
+ filter: function (entry) {
45
+ return (
46
+ entry?.info?.container !== MAINTENANCE &&
47
+ entry?.last?.snap?.stats?.hashrate_mhs?.t_5m != null
48
+ )
49
+ }
50
+ },
51
+ hashrate_mhs_1m_cnt_active: {
52
+ op: 'cnt',
53
+ src: 'last.snap.stats.hashrate_mhs.t_5m',
54
+ filter: function (entry) {
55
+ return entry?.last?.snap?.stats?.status === STATUS.MINING
56
+ }
57
+ },
58
+ offline_or_sleeping_miners_cnt: {
59
+ op: 'cnt',
60
+ filter: function (entry) {
61
+ return (
62
+ entry?.info?.container !== MAINTENANCE &&
63
+ [STATUS.OFFLINE, STATUS.SLEEPING].includes(entry?.last?.snap?.stats?.status)
64
+ )
65
+ }
66
+ },
67
+ online_or_minor_error_miners_cnt: {
68
+ op: 'cnt',
69
+ filter: function (entry) {
70
+ return (
71
+ entry?.info?.container !== MAINTENANCE &&
72
+ entry?.last?.snap?.stats?.status === STATUS.MINING
73
+ )
74
+ }
75
+ },
76
+ error_miners_cnt: {
77
+ op: 'cnt',
78
+ filter: function (entry) {
79
+ return (
80
+ entry?.info?.container !== MAINTENANCE &&
81
+ entry?.last?.snap?.stats?.status === STATUS.ERROR
82
+ )
83
+ }
84
+ },
85
+ not_mining_miners_cnt: {
86
+ op: 'cnt',
87
+ filter: function (entry) {
88
+ return (
89
+ entry?.info?.container !== MAINTENANCE &&
90
+ entry?.last?.snap?.stats?.status === STATUS.NOT_MINING
91
+ )
92
+ }
93
+ },
94
+ power_w_sum: {
95
+ op: 'sum',
96
+ src: 'last.snap.stats.power_w'
97
+ },
98
+ power_w_avg: {
99
+ op: 'avg',
100
+ src: 'last.snap.stats.power_w'
101
+ },
102
+ power_w_type_group_sum: {
103
+ op: 'group_sum',
104
+ src: 'last.snap.stats.power_w',
105
+ group: groupBy('type'),
106
+ filter: (entry) => {
107
+ return entry?.info?.container !== MAINTENANCE
108
+ }
109
+ },
110
+ power_w_type_group_avg: {
111
+ op: 'group_avg',
112
+ src: 'last.snap.stats.power_w',
113
+ group: groupBy('type'),
114
+ filter: (entry) => {
115
+ return entry?.info?.container !== MAINTENANCE
116
+ }
117
+ },
118
+ power_w_container_group_sum: {
119
+ op: 'group_sum',
120
+ src: 'last.snap.stats.power_w',
121
+ group: groupBy('info.container')
122
+ },
123
+ power_w_container_group_avg: {
124
+ op: 'group_avg',
125
+ src: 'last.snap.stats.power_w',
126
+ group: groupBy('info.container')
127
+ },
128
+ uptime_ms_avg: {
129
+ op: 'avg',
130
+ src: 'last.snap.stats.uptime_ms'
131
+ },
132
+ frequency_mhz_avg: {
133
+ op: 'avg',
134
+ src: 'last.snap.stats.frequency_mhz.avg'
135
+ },
136
+ efficiency_w_ths_avg: {
137
+ op: 'avg',
138
+ src: 'last.snap.stats.efficiency_w_ths'
139
+ },
140
+ temperature_c_avg: {
141
+ op: 'avg',
142
+ src: 'last.snap.stats.temperature_c.avg'
143
+ },
144
+ temperature_c_group_avg: {
145
+ op: 'group_avg',
146
+ src: 'last.snap.stats.temperature_c.avg',
147
+ group: groupBy('info.container')
148
+ },
149
+ temperature_c_group_max: {
150
+ op: 'group_max',
151
+ src: 'last.snap.stats.temperature_c.max',
152
+ group: groupBy('info.container')
153
+ },
154
+ offline_cnt: {
155
+ op: 'group_cnt',
156
+ group: groupBy('info.container'),
157
+ filter: (entry) => {
158
+ return (
159
+ entry?.info?.container !== MAINTENANCE &&
160
+ entry?.last?.snap?.stats?.status === STATUS.OFFLINE
161
+ )
162
+ }
163
+ },
164
+ error_cnt: {
165
+ op: 'group_cnt',
166
+ group: groupBy('info.container'),
167
+ filter: (entry) => {
168
+ return (
169
+ entry?.info?.container !== MAINTENANCE &&
170
+ entry?.last?.snap?.stats?.status === STATUS.ERROR
171
+ )
172
+ }
173
+ },
174
+ not_mining_cnt: {
175
+ op: 'group_cnt',
176
+ group: groupBy('info.container'),
177
+ filter: (entry) => {
178
+ return (
179
+ entry?.info?.container !== MAINTENANCE &&
180
+ entry?.last?.snap?.stats?.status === STATUS.NOT_MINING
181
+ )
182
+ }
183
+ },
184
+ power_mode_sleep_cnt: {
185
+ op: 'group_cnt',
186
+ group: groupBy('info.container'),
187
+ filter: (entry) => {
188
+ return entry?.last?.snap?.stats?.status === STATUS.SLEEPING
189
+ }
190
+ },
191
+ power_mode_low_cnt: {
192
+ op: 'group_cnt',
193
+ group: groupBy('info.container'),
194
+ filter: (entry) => {
195
+ return entry?.last?.snap?.stats?.status === STATUS.MINING && entry?.last?.snap?.config?.power_mode === POWER_MODE.LOW
196
+ }
197
+ },
198
+ power_mode_normal_cnt: {
199
+ op: 'group_cnt',
200
+ group: groupBy('info.container'),
201
+ filter: (entry) => {
202
+ return entry?.last?.snap?.stats?.status === STATUS.MINING && entry?.last?.snap?.config?.power_mode === POWER_MODE.NORMAL
203
+ }
204
+ },
205
+ power_mode_high_cnt: {
206
+ op: 'group_cnt',
207
+ group: groupBy('info.container'),
208
+ filter: (entry) => {
209
+ return entry?.last?.snap?.stats?.status === STATUS.MINING && entry?.last?.snap?.config?.power_mode === POWER_MODE.HIGH
210
+ }
211
+ },
212
+ power_mode_low_include_error_cnt: {
213
+ op: 'group_cnt',
214
+ group: groupBy('info.container'),
215
+ filter: (entry) => {
216
+ return hasErrorAndPositiveHashrate(entry) && entry?.last?.snap?.config?.power_mode === POWER_MODE.LOW
217
+ }
218
+ },
219
+ power_mode_normal_include_error_cnt: {
220
+ op: 'group_cnt',
221
+ group: groupBy('info.container'),
222
+ filter: (entry) => {
223
+ return hasErrorAndPositiveHashrate(entry) && entry?.last?.snap?.config?.power_mode === POWER_MODE.NORMAL
224
+ }
225
+ },
226
+ power_mode_high_include_error_cnt: {
227
+ op: 'group_cnt',
228
+ group: groupBy('info.container'),
229
+ filter: (entry) => {
230
+ return hasErrorAndPositiveHashrate(entry) && entry?.last?.snap?.config?.power_mode === POWER_MODE.HIGH
231
+ }
232
+ },
233
+ type_cnt: {
234
+ op: 'group_cnt',
235
+ group: groupBy('type'),
236
+ filter: (entry) => {
237
+ return entry?.info?.container !== MAINTENANCE && entry?.last?.snap
238
+ }
239
+ },
240
+ offline_type_cnt: {
241
+ op: 'group_cnt',
242
+ group: groupBy('type'),
243
+ filter: (entry) => {
244
+ return (
245
+ entry?.info?.container !== MAINTENANCE &&
246
+ entry?.last?.snap?.stats?.status === STATUS.OFFLINE
247
+ )
248
+ }
249
+ },
250
+ maintenance_type_cnt: {
251
+ op: 'group_cnt',
252
+ group: groupBy('type'),
253
+ filter: (entry) => {
254
+ return entry?.info?.container === MAINTENANCE
255
+ }
256
+ },
257
+ online_positive_hashrate_type_cnt: {
258
+ op: 'group_cnt',
259
+ group: groupBy('type'),
260
+ filter: (entry) => {
261
+ const { status, hashrate_mhs: hashrateMHS } = entry?.last?.snap?.stats || {}
262
+ return (
263
+ entry?.info?.container !== MAINTENANCE &&
264
+ status !== STATUS.OFFLINE &&
265
+ hashrateMHS?.t_5m > 0
266
+ )
267
+ }
268
+ },
269
+ online_without_hashrate_type_cnt: {
270
+ op: 'group_cnt',
271
+ group: groupBy('type'),
272
+ filter: (entry) => {
273
+ const { status, hashrate_mhs: hashrateMHS } = entry?.last?.snap?.stats || {}
274
+ return (
275
+ entry?.info?.container !== MAINTENANCE &&
276
+ status !== STATUS.OFFLINE &&
277
+ (!hashrateMHS?.t_5m || hashrateMHS?.t_5m === 0)
278
+ )
279
+ }
280
+ },
281
+ error_type_cnt: {
282
+ op: 'group_cnt',
283
+ group: groupBy('type'),
284
+ filter: (entry) => {
285
+ return (
286
+ entry?.info?.container !== MAINTENANCE &&
287
+ entry?.last?.snap?.stats?.status === STATUS.ERROR
288
+ )
289
+ }
290
+ },
291
+ not_mining_type_cnt: {
292
+ op: 'group_cnt',
293
+ group: groupBy('type'),
294
+ filter: (entry) => {
295
+ return (
296
+ entry?.info?.container !== MAINTENANCE &&
297
+ entry?.last?.snap?.stats?.status === STATUS.NOT_MINING
298
+ )
299
+ }
300
+ },
301
+ power_mode_sleep_type_cnt: {
302
+ op: 'group_cnt',
303
+ group: groupBy('type'),
304
+ filter: (entry) => {
305
+ return entry?.last?.snap?.stats?.status === STATUS.SLEEPING
306
+ }
307
+ },
308
+ power_mode_low_type_cnt: {
309
+ op: 'group_cnt',
310
+ group: groupBy('type'),
311
+ filter: (entry) => {
312
+ return entry?.last?.snap?.stats?.status === STATUS.MINING && entry?.last?.snap?.config?.power_mode === POWER_MODE.LOW
313
+ }
314
+ },
315
+ power_mode_normal_type_cnt: {
316
+ op: 'group_cnt',
317
+ group: groupBy('type'),
318
+ filter: (entry) => {
319
+ return entry?.last?.snap?.stats?.status === STATUS.MINING && entry?.last?.snap?.config?.power_mode === POWER_MODE.NORMAL
320
+ }
321
+ },
322
+ power_mode_high_type_cnt: {
323
+ op: 'group_cnt',
324
+ group: groupBy('type'),
325
+ filter: (entry) => {
326
+ return entry?.last?.snap?.stats?.status === STATUS.MINING && entry?.last?.snap?.config?.power_mode === POWER_MODE.HIGH
327
+ }
328
+ },
329
+ hashrate_mhs_1m_type_group_sum: {
330
+ op: 'group_sum',
331
+ src: 'last.snap.stats.hashrate_mhs.t_5m',
332
+ group: groupBy('type'),
333
+ filter: (entry) => {
334
+ return entry?.info?.container !== MAINTENANCE
335
+ }
336
+ },
337
+ hashrate_mhs_1m_type_group_avg: {
338
+ op: 'group_avg',
339
+ src: 'last.snap.stats.hashrate_mhs.t_5m',
340
+ group: groupBy('type')
341
+ },
342
+ efficiency_w_ths_type_group_avg: {
343
+ op: 'group_avg',
344
+ src: 'last.snap.stats.efficiency_w_ths',
345
+ group: groupBy('type')
346
+ },
347
+ hashrate_mhs_1m_container_group_sum: {
348
+ op: 'group_sum',
349
+ src: 'last.snap.stats.hashrate_mhs.t_5m',
350
+ group: groupBy('info.container')
351
+ },
352
+ hashrate_mhs_1m_container_group_avg: {
353
+ op: 'group_avg',
354
+ src: 'last.snap.stats.hashrate_mhs.t_5m',
355
+ group: groupBy('info.container')
356
+ },
357
+ efficiency_w_ths_container_group_avg: {
358
+ op: 'group_avg',
359
+ src: 'last.snap.stats.efficiency_w_ths',
360
+ group: groupBy('info.container')
361
+ },
362
+ hashrate_mhs_5m_active_container_group_cnt: {
363
+ op: 'group_cnt',
364
+ group: groupBy('info.container'),
365
+ filter: (entry) => entry?.last?.snap?.stats?.hashrate_mhs?.t_5m
366
+ },
367
+ nominal_hashrate_mhs_avg: {
368
+ op: 'avg',
369
+ src: 'info.nominalHashrateMhs'
370
+ },
371
+ nominal_efficiency_w_ths_avg: {
372
+ op: 'avg',
373
+ src: 'last.snap.stats.nominal_efficiency_w_ths'
374
+ },
375
+ nominal_hashrate_mhs_sum: {
376
+ op: 'sum',
377
+ src: 'info.nominalHashrateMhs'
378
+ },
379
+ nominal_efficiency_w_ths_sum: {
380
+ op: 'sum',
381
+ src: 'last.snap.stats.nominal_efficiency_w_ths'
382
+ },
383
+ hashrate_mhs_5m_sum: {
384
+ op: 'sum',
385
+ src: 'last.snap.stats.hashrate_mhs.t_5m'
386
+ },
387
+ hashrate_mhs_5m_avg: {
388
+ op: 'avg',
389
+ src: 'last.snap.stats.hashrate_mhs.t_5m'
390
+ },
391
+ hashrate_mhs_5m_cnt: {
392
+ op: 'cnt',
393
+ src: 'last.snap.stats.hashrate_mhs.t_5m'
394
+ },
395
+ hashrate_mhs_5m_cnt_active: {
396
+ op: 'cnt',
397
+ src: 'last.snap.stats.hashrate_mhs.t_5m',
398
+ filter: function (entry) {
399
+ return entry?.last?.snap?.stats?.status === STATUS.MINING
400
+ }
401
+ },
402
+ hashrate_mhs_5m_type_group_sum: {
403
+ op: 'group_sum',
404
+ src: 'last.snap.stats.hashrate_mhs.t_5m',
405
+ group: groupBy('type')
406
+ },
407
+ hashrate_mhs_5m_type_group_avg: {
408
+ op: 'group_avg',
409
+ src: 'last.snap.stats.hashrate_mhs.t_5m',
410
+ group: groupBy('type')
411
+ },
412
+ hashrate_mhs_5m_container_group_sum: {
413
+ op: 'group_sum',
414
+ src: 'last.snap.stats.hashrate_mhs.t_5m',
415
+ group: groupBy('info.container')
416
+ },
417
+ hashrate_mhs_5m_container_group_avg: {
418
+ op: 'group_avg',
419
+ src: 'last.snap.stats.hashrate_mhs.t_5m',
420
+ group: groupBy('info.container')
421
+ },
422
+ miner_inventory_status_group_cnt: {
423
+ op: 'group_cnt',
424
+ group: groupBy('info.status')
425
+ },
426
+ miner_inventory_location_group_cnt: {
427
+ op: 'group_cnt',
428
+ group: groupBy('info.location')
429
+ }
430
+ }
431
+
432
+ const CONTAINER_DEFAULT_OPS = {
433
+ ...DEFAULT_OPS,
434
+ container_status: {
435
+ op: 'group',
436
+ src: 'last.snap.stats.status',
437
+ group: groupBy('info.container')
438
+ },
439
+ container_power_w_sum: {
440
+ op: 'sum',
441
+ src: 'last.snap.stats.power_w'
442
+ },
443
+ container_power_w: {
444
+ op: 'group',
445
+ src: 'last.snap.stats.power_w',
446
+ group: groupBy('info.container')
447
+ },
448
+ container_nominal_hashrate_mhs_sum: {
449
+ op: 'sum',
450
+ src: 'info.nominalHashrateMhs'
451
+ },
452
+ container_nominal_hashrate_mhs_avg: {
453
+ op: 'avg',
454
+ src: 'info.nominalHashrateMhs'
455
+ },
456
+ container_nominal_efficiency_w_ths_avg: {
457
+ op: 'avg',
458
+ src: 'info.nominalEfficiencyWThs'
459
+ },
460
+ container_nominal_miner_capacity_sum: {
461
+ op: 'sum',
462
+ src: 'info.nominalMinerCapacity'
463
+ }
464
+ }
465
+
466
+ module.exports = {
467
+ conf: CONF,
468
+ minerConf: MINER_CONF,
469
+ specs: {
470
+ default: { ops: DEFAULT_OPS },
471
+ miner_default: { ops: MINER_DEFAULT_OPS },
472
+ container_default: { ops: CONTAINER_DEFAULT_OPS },
473
+ powermeter_default: { ops: DEFAULT_OPS },
474
+ sensor_default: { ops: DEFAULT_OPS }
475
+ }
476
+ }
@@ -0,0 +1,65 @@
1
+ 'use strict'
2
+
3
+ const STAT_RTD = 'stat-rtd'
4
+ const MAIN_DB = 'main'
5
+
6
+ const TIME_PERIODS_MS = {
7
+ H: 60 * 60 * 1000,
8
+ D: 24 * 60 * 60 * 1000,
9
+ W: 7 * 24 * 60 * 60 * 1000,
10
+ M: 30 * 24 * 60 * 60 * 1000
11
+ }
12
+
13
+ const OPTIONAL_CONFIGS = []
14
+ const RPC_METHODS = {}
15
+
16
+ const MAINTENANCE = 'maintenance'
17
+
18
+ const STATUS = {
19
+ OFFLINE: 'offline',
20
+ SLEEPING: 'sleeping',
21
+ MINING: 'mining',
22
+ ERROR: 'error',
23
+ NOT_MINING: 'not_mining'
24
+ }
25
+
26
+ const POWER_MODE = {
27
+ LOW: 'low',
28
+ NORMAL: 'normal',
29
+ HIGH: 'high',
30
+ SLEEP: 'sleep'
31
+ }
32
+
33
+ const DEFAULT_THRESHOLD_HASHRATE = 50000000
34
+
35
+ const STAT_SHARES_1M = 'stat-shares-1m'
36
+ const STAT_SHARES_30M = 'stat-shares-30m'
37
+ const STAT_30M = 'stat-30m'
38
+ const MINER_TAG = 't-miner'
39
+ const STAT_STARTUP_STATUS = 'stat-startup'
40
+ const STAT_5M = 'stat-5m'
41
+
42
+ const RUNNING_STATUS = {
43
+ RUNNING: 'running',
44
+ STOPPED: 'stopped',
45
+ ERROR: 'error'
46
+ }
47
+
48
+ module.exports = {
49
+ STAT_RTD,
50
+ OPTIONAL_CONFIGS,
51
+ RPC_METHODS,
52
+ MAIN_DB,
53
+ TIME_PERIODS_MS,
54
+ MAINTENANCE,
55
+ POWER_MODE,
56
+ STATUS,
57
+ DEFAULT_THRESHOLD_HASHRATE,
58
+ STAT_SHARES_1M,
59
+ STAT_SHARES_30M,
60
+ STAT_30M,
61
+ MINER_TAG,
62
+ STAT_STARTUP_STATUS,
63
+ STAT_5M,
64
+ RUNNING_STATUS
65
+ }
@@ -0,0 +1,84 @@
1
+ 'use strict'
2
+
3
+ const Thing = require('./thing')
4
+
5
+ class Container extends Thing {
6
+ constructor (opts = {}) {
7
+ super('container', opts)
8
+ }
9
+
10
+ // Container write action validator
11
+ validateWriteAction (...params) {
12
+ const [action, ...args] = params
13
+
14
+ if (action === 'switchContainer') {
15
+ const [enabled] = args
16
+ if (typeof enabled !== 'boolean') {
17
+ throw new Error('ERR_SWITCH_CONTAINER_ENABLED_INVALID')
18
+ }
19
+ }
20
+
21
+ if (action === 'switchSocket') {
22
+ if (Array.isArray(args[0])) {
23
+ args[0].forEach((arg) => {
24
+ const [pduIndex, socketIndex, enabled] = arg
25
+
26
+ if (typeof pduIndex !== 'string') {
27
+ throw new Error('ERR_SWITCH_SOCKET_PDU_INDEX_INVALID')
28
+ }
29
+ if (typeof socketIndex !== 'string') {
30
+ throw new Error('ERR_SWITCH_SOCKET_SOCKET_INDEX_INVALID')
31
+ }
32
+ if (typeof enabled !== 'boolean') {
33
+ throw new Error('ERR_SWITCH_SOCKET_ENABLED_INVALID')
34
+ }
35
+ })
36
+ } else {
37
+ throw new Error('ERR_SWITCH_SOCKET_ARGS_INVALID')
38
+ }
39
+ }
40
+
41
+ if (action === 'switchCoolingSystem') {
42
+ const [enabled] = args
43
+ if (typeof enabled !== 'boolean') {
44
+ throw new Error('ERR_SWITCH_COOLING_SYSTEM_ENABLED_INVALID')
45
+ }
46
+ }
47
+
48
+ return 1
49
+ }
50
+
51
+ async turnOnContainer (cooling, devices) {
52
+ throw new Error('ERR_NO_IMPL')
53
+ }
54
+
55
+ async turnOffContainer () {
56
+ throw new Error('ERR_NO_IMPL')
57
+ }
58
+
59
+ async switchContainer (enabled) {
60
+ throw new Error('ERR_NO_IMPL')
61
+ }
62
+
63
+ async switchCoolingSystem (enabled) {
64
+ throw new Error('ERR_NO_IMPL')
65
+ }
66
+
67
+ async switchSocket (args) {
68
+ throw new Error('ERR_NO_IMPL')
69
+ }
70
+
71
+ async turnOnCoolingSystem () {
72
+ throw new Error('ERR_NO_IMPL')
73
+ }
74
+
75
+ async turnOffCoolingSystem () {
76
+ throw new Error('ERR_NO_IMPL')
77
+ }
78
+
79
+ async resetAlarm () {
80
+ throw new Error('ERR_NO_IMPL')
81
+ }
82
+ }
83
+
84
+ module.exports = Container