@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.
- package/LICENSE +202 -0
- package/README.md +572 -0
- package/index.js +519 -0
- package/lib/address-policy.js +124 -0
- package/lib/local-discovery.js +321 -0
- package/lib/services/actions.service.js +68 -0
- package/lib/services/alerts.service.js +207 -0
- package/lib/services/comments.service.js +118 -0
- package/lib/services/log-history.service.js +307 -0
- package/lib/services/logs.service.js +249 -0
- package/lib/services/pool-utils/constants.js +20 -0
- package/lib/services/pool-utils/time.js +49 -0
- package/lib/services/pool.service.js +397 -0
- package/lib/services/provisioning.service.js +420 -0
- package/lib/services/settings.service.js +26 -0
- package/lib/services/snaps.service.js +181 -0
- package/lib/services/stats.service.js +205 -0
- package/lib/stats/README.md +80 -0
- package/lib/stats/index.js +57 -0
- package/lib/stats/ops/alerts_aggr.js +40 -0
- package/lib/stats/ops/alerts_group_cnt.js +43 -0
- package/lib/stats/ops/arr_concat.js +27 -0
- package/lib/stats/ops/array_obj_calc.js +41 -0
- package/lib/stats/ops/avg.js +42 -0
- package/lib/stats/ops/cnt.js +19 -0
- package/lib/stats/ops/group.js +38 -0
- package/lib/stats/ops/group_avg.js +53 -0
- package/lib/stats/ops/group_cnt.js +38 -0
- package/lib/stats/ops/group_max.js +40 -0
- package/lib/stats/ops/group_multiple_stats.js +40 -0
- package/lib/stats/ops/group_sum.js +40 -0
- package/lib/stats/ops/index.js +35 -0
- package/lib/stats/ops/nested_obj_concat.js +54 -0
- package/lib/stats/ops/obj_concat.js +33 -0
- package/lib/stats/ops/sum.js +27 -0
- package/lib/stats/utils.js +99 -0
- package/lib/templates/alerts.js +128 -0
- package/lib/templates/stats.js +476 -0
- package/lib/things/constants.js +65 -0
- package/lib/things/container.js +84 -0
- package/lib/things/miner.js +190 -0
- package/lib/things/powermeter.js +30 -0
- package/lib/things/sensor.js +18 -0
- package/lib/things/thing.js +93 -0
- package/lib/utils.js +603 -0
- package/lib/worker-infra.js +221 -0
- package/package.json +64 -1
- package/services.js +246 -0
- package/utils/compose-yaml.js +56 -0
- package/utils/constants.js +30 -0
- package/utils/index.js +29 -0
- package/utils/initialize.js +148 -0
- package/utils/service-bootstrap.js +271 -0
- 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
|