@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,190 @@
1
+ 'use strict'
2
+
3
+ const Thing = require('./thing')
4
+ const { sumPoolsShares } = require('../utils')
5
+
6
+ class Miner extends Thing {
7
+ constructor (opts = {}) {
8
+ super('miner', opts)
9
+
10
+ this.deviceDataCache = {}
11
+ this.cachedShares = { accepted: 0, rejected: 0, stale: 0 }
12
+ }
13
+
14
+ // Miner data fetching methods
15
+ async getPools () {
16
+ throw new Error('Not implemented')
17
+ }
18
+
19
+ // Miner write action validator
20
+ validateWriteAction (...params) {
21
+ const [action, ...args] = params
22
+
23
+ if (action === 'setLED') {
24
+ const [enabled] = args
25
+ if (typeof enabled !== 'boolean') {
26
+ throw new Error('ERR_SET_LED_ENABLED_INVALID')
27
+ }
28
+ }
29
+
30
+ return 1
31
+ }
32
+
33
+ checkSamePools (newPools, oldPools) {
34
+ if (newPools.length !== oldPools.length) {
35
+ return false
36
+ }
37
+
38
+ for (const pool of newPools) {
39
+ const oldPool = oldPools.find(p => p.url === pool.url)
40
+
41
+ if (oldPool === undefined) {
42
+ return false
43
+ }
44
+
45
+ if (pool.worker_name !== oldPool.username) {
46
+ return false
47
+ }
48
+ }
49
+
50
+ return true
51
+ }
52
+
53
+ // Miner control methods
54
+ preProcessPoolData (pools, appendId = true) {
55
+ if (!Array.isArray(pools)) throw new Error('ERR_INVALID_ARG_TYPE')
56
+
57
+ if (appendId) {
58
+ pools = pools.map((pool) => ({
59
+ ...pool,
60
+ worker_name: `${pool.worker_name}.${this.opts.id}`
61
+ }))
62
+ }
63
+
64
+ if (pools.length < 3) {
65
+ for (let i = pools.length; i < 3; i++) {
66
+ pools.push({
67
+ url: '',
68
+ worker_name: '',
69
+ worker_password: ''
70
+ })
71
+ }
72
+ }
73
+
74
+ return pools
75
+ }
76
+
77
+ _prepPools (pools, appendId, oldPools) {
78
+ pools = this.preProcessPoolData(pools, appendId)
79
+
80
+ if (oldPools) {
81
+ if (this.checkSamePools(pools, oldPools)) {
82
+ return false
83
+ }
84
+ }
85
+
86
+ return pools
87
+ }
88
+
89
+ async setupPools () {
90
+ try {
91
+ await this.setPools(this.conf.pools, true)
92
+ return { success: true }
93
+ } catch (e) {
94
+ return { success: false, error_msg: e.message }
95
+ }
96
+ }
97
+
98
+ async powerOn () {
99
+ throw new Error('Not implemented')
100
+ }
101
+
102
+ async powerOff () {
103
+ throw new Error('Not implemented')
104
+ }
105
+
106
+ async reboot () {
107
+ throw new Error('Not implemented')
108
+ }
109
+
110
+ async setPools (pools) {
111
+ throw new Error('Not implemented')
112
+ }
113
+
114
+ async setFanSpeed (speed) {
115
+ throw new Error('Not implemented')
116
+ }
117
+
118
+ async setPowerMode (mode) {
119
+ throw new Error('Not implemented')
120
+ }
121
+
122
+ async updateFirmware (firmwareFile) {
123
+ throw new Error('Not implemented')
124
+ }
125
+
126
+ async fetchDeviceData (fn, cacheTime = 5000) {
127
+ const lastFetched = this.deviceDataCache[fn.name]?.lastFetch
128
+ if (!lastFetched || lastFetched < (Date.now() - cacheTime)) {
129
+ const data = await fn.call(this)
130
+ this.deviceDataCache[fn.name] = { data, lastFetch: Date.now() }
131
+ }
132
+
133
+ return this.deviceDataCache[fn.name].data
134
+ }
135
+
136
+ _getStatus (errors, stats) {
137
+ // no-op
138
+ }
139
+
140
+ _isSuspended (stats) {
141
+ // no-op
142
+ }
143
+
144
+ _calcPowerW (stats) {
145
+ // no-op
146
+ }
147
+
148
+ _calcAvgTemp (stats) {
149
+ // no-op
150
+ }
151
+
152
+ _getPowerMode (stats) {
153
+ // no-op
154
+ }
155
+
156
+ _calcEfficiency (stats, summary) {
157
+ // no-op
158
+ }
159
+
160
+ _calcHashrates (stats) {
161
+ // no-op
162
+ }
163
+
164
+ _calcNewShares (pools) {
165
+ // sometimes randomly device returns empty or no pools, skip such cases
166
+ if (!Array.isArray(pools) || !pools.length) {
167
+ return { accepted: 0, rejected: 0, stale: 0 }
168
+ }
169
+
170
+ const currentShares = {
171
+ accepted: sumPoolsShares(pools, 'accepted'),
172
+ rejected: sumPoolsShares(pools, 'rejected'),
173
+ stale: sumPoolsShares(pools, 'stale')
174
+ }
175
+
176
+ // calculate newly added shares since the last snap
177
+ const newShares = {
178
+ accepted: currentShares.accepted >= this.cachedShares.accepted ? currentShares.accepted - this.cachedShares.accepted : currentShares.accepted,
179
+ rejected: currentShares.rejected >= this.cachedShares.rejected ? currentShares.rejected - this.cachedShares.rejected : currentShares.rejected,
180
+ stale: currentShares.stale >= this.cachedShares.stale ? currentShares.stale - this.cachedShares.stale : currentShares.stale
181
+ }
182
+
183
+ // cache current shares
184
+ this.cachedShares = { ...currentShares }
185
+
186
+ return newShares
187
+ }
188
+ }
189
+
190
+ module.exports = Miner
@@ -0,0 +1,30 @@
1
+ 'use strict'
2
+
3
+ const Thing = require('./thing')
4
+
5
+ class PowerMeter extends Thing {
6
+ constructor (opts) {
7
+ super('powermeter', opts)
8
+
9
+ this.cache = null
10
+ this.cacheTime = 0
11
+ }
12
+
13
+ async getRealtimeData () {
14
+ // snap is read at short intervals, return data from cache
15
+ return await this._prepSnap(true)
16
+ }
17
+
18
+ /**
19
+ * Calculate the average tension (voltage) from three phase-to-phase measurements
20
+ * @param {number} l1L2 - Voltage between L1 and L2
21
+ * @param {number} l2L3 - Voltage between L2 and L3
22
+ * @param {number} l3L1 - Voltage between L3 and L1
23
+ * @returns {number} Average tension across all three phases
24
+ */
25
+ calculateTension (l1L2, l2L3, l3L1) {
26
+ return (l1L2 + l2L3 + l3L1) / 3
27
+ }
28
+ }
29
+
30
+ module.exports = PowerMeter
@@ -0,0 +1,18 @@
1
+ 'use strict'
2
+
3
+ const Thing = require('./thing')
4
+
5
+ class Sensor extends Thing {
6
+ constructor (opts) {
7
+ super('sensor', opts)
8
+
9
+ this.cache = null
10
+ }
11
+
12
+ async getRealtimeData () {
13
+ // snap is read at short intervals, return data from cache
14
+ return await this._prepSnap(true)
15
+ }
16
+ }
17
+
18
+ module.exports = Sensor
@@ -0,0 +1,93 @@
1
+ 'use strict'
2
+
3
+ const debug = require('debug')
4
+ const EventEmitter = require('events')
5
+
6
+ class Thing extends EventEmitter {
7
+ constructor (type, { lastSeenTimeout = 30000, conf = {}, ...opts }) {
8
+ super()
9
+ this._lastSeen = null
10
+ this._errorLog = []
11
+ this._type = type
12
+ this.debug = debug(`thing:${type}`)
13
+ this.conf = conf
14
+ this.opts = {
15
+ lastSeenTimeout,
16
+ timeout: conf.timeout || 10000,
17
+ ...opts
18
+ }
19
+ this.lastSnap = null
20
+ }
21
+
22
+ debugError (data, e) {
23
+ this.debug(data, e)
24
+ }
25
+
26
+ updateLastSeen () {
27
+ this._lastSeen = Date.now()
28
+ }
29
+
30
+ isThingOnline () {
31
+ // if thing is offline for more than lastSeenTimeout seconds, it is considered offline
32
+ return this._lastSeen !== null && Date.now() - this._lastSeen < this.opts.lastSeenTimeout
33
+ }
34
+
35
+ validateWriteAction (...params) {
36
+ throw new Error('ERR_NO_IMPL')
37
+ }
38
+
39
+ async _prepSnap () {
40
+ throw new Error('ERR_NO_IMPL')
41
+ }
42
+
43
+ _handleErrorUpdates (errors) {
44
+ this._errorLog.length = 0
45
+ this._errorLog.push(...errors)
46
+ }
47
+
48
+ async getSnap () {
49
+ let snap
50
+ try {
51
+ const data = await this._prepSnap()
52
+
53
+ snap = {
54
+ success: true,
55
+ raw_errors: this._errorLog,
56
+ stats: data.stats,
57
+ config: data.config
58
+ }
59
+ } catch (err) {
60
+ this.debugError('getSnap error', err)
61
+ if (this.isThingOnline() && err.message !== 'ERR_OFFLINE') {
62
+ snap = {
63
+ success: false,
64
+ stats: {
65
+ status: 'error',
66
+ errors: [
67
+ {
68
+ msg: err.message,
69
+ timestamp: Date.now()
70
+ }
71
+ ]
72
+ }
73
+ }
74
+ } else {
75
+ snap = {
76
+ success: false,
77
+ stats: {
78
+ status: 'offline'
79
+ }
80
+ }
81
+ }
82
+ }
83
+
84
+ this.lastSnap = snap
85
+ return snap
86
+ }
87
+
88
+ async getRealtimeData () {
89
+ return this.lastSnap
90
+ }
91
+ }
92
+
93
+ module.exports = Thing