homebridge-lib 6.3.6 → 6.3.8
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/README.md +1 -6
- package/cli/hap.js +2 -80
- package/cli/json.js +2 -154
- package/cli/sysinfo.js +2 -69
- package/cli/upnp.js +2 -138
- package/index.js +41 -99
- package/lib/AccessoryDelegate.js +1 -1
- package/lib/AdaptiveLighting.js +3 -3
- package/lib/Delegate.js +2 -1
- package/lib/EveHomeKitTypes.js +2 -2
- package/lib/MyHomeKitTypes.js +2 -2
- package/lib/Platform.js +7 -5
- package/lib/ServiceDelegate/AccessoryInformation.js +1 -3
- package/lib/ServiceDelegate/Battery.js +1 -3
- package/lib/ServiceDelegate/Dummy.js +1 -3
- package/lib/ServiceDelegate/History.js +6 -11
- package/lib/ServiceDelegate/ServiceLabel.js +1 -3
- package/lib/UiServer.js +1 -2
- package/package.json +4 -6
- package/lib/Colour.js +0 -323
- package/lib/CommandLineParser.js +0 -311
- package/lib/CommandLineTool.js +0 -328
- package/lib/HttpClient.js +0 -478
- package/lib/JsonFormatter.js +0 -200
- package/lib/OptionParser.js +0 -886
- package/lib/SystemInfo.js +0 -522
- package/lib/UpnpClient.js +0 -217
package/lib/SystemInfo.js
DELETED
|
@@ -1,522 +0,0 @@
|
|
|
1
|
-
// homebridge-lib/lib/SystemInfo.js
|
|
2
|
-
//
|
|
3
|
-
// Library for Homebridge plugins.
|
|
4
|
-
// Copyright © 2019-2023 Erik Baauw. All rights reserved.
|
|
5
|
-
|
|
6
|
-
'use strict'
|
|
7
|
-
|
|
8
|
-
const events = require('events')
|
|
9
|
-
const { exec, execFile } = require('child_process')
|
|
10
|
-
const fs = require('fs').promises
|
|
11
|
-
const os = require('os')
|
|
12
|
-
const semver = require('semver')
|
|
13
|
-
|
|
14
|
-
const homebridgeLib = require('../index')
|
|
15
|
-
|
|
16
|
-
const rpiInfo = {
|
|
17
|
-
manufacturers: {
|
|
18
|
-
0: 'Sony UK',
|
|
19
|
-
1: 'Egoman',
|
|
20
|
-
2: 'Embest',
|
|
21
|
-
3: 'Sony Japan',
|
|
22
|
-
4: 'Embest',
|
|
23
|
-
5: 'Stadium'
|
|
24
|
-
},
|
|
25
|
-
memorySizes: {
|
|
26
|
-
0: '256MB',
|
|
27
|
-
1: '512MB',
|
|
28
|
-
2: '1GB',
|
|
29
|
-
3: '2GB',
|
|
30
|
-
4: '4GB',
|
|
31
|
-
5: '8GB'
|
|
32
|
-
},
|
|
33
|
-
models: {
|
|
34
|
-
0: 'A',
|
|
35
|
-
1: 'B',
|
|
36
|
-
2: 'A+',
|
|
37
|
-
3: 'B+',
|
|
38
|
-
4: '2B',
|
|
39
|
-
5: 'Alpha', // early prototype
|
|
40
|
-
6: 'CM1',
|
|
41
|
-
8: '3B',
|
|
42
|
-
9: 'Zero',
|
|
43
|
-
10: 'CM3',
|
|
44
|
-
12: 'Zero W',
|
|
45
|
-
13: '3B+',
|
|
46
|
-
14: '3A+',
|
|
47
|
-
// 15: '', // Internal use only
|
|
48
|
-
16: 'CM3+',
|
|
49
|
-
17: '4B',
|
|
50
|
-
18: 'Zero 2 W',
|
|
51
|
-
19: '400',
|
|
52
|
-
20: 'CM4',
|
|
53
|
-
21: 'CM4S'
|
|
54
|
-
},
|
|
55
|
-
processors: {
|
|
56
|
-
0: 'BCM2835',
|
|
57
|
-
1: 'BCM2836',
|
|
58
|
-
2: 'BCM2837',
|
|
59
|
-
3: 'BCM2711'
|
|
60
|
-
},
|
|
61
|
-
oldRevisions: {
|
|
62
|
-
2: { model: 'B', revision: '1.0', memory: '256MB', manufacturer: 'Egoman' },
|
|
63
|
-
3: { model: 'B', revision: '1.0', memory: '256MB', manufacturer: 'Egoman' },
|
|
64
|
-
4: { model: 'B', revision: '2.0', memory: '256MB', manufacturer: 'Sony UK' },
|
|
65
|
-
5: { model: 'B', revision: '2.0', memory: '256MB', manufacturer: 'Qisda' },
|
|
66
|
-
6: { model: 'B', revision: '2.0', memory: '256MB', manufacturer: 'Egoman' },
|
|
67
|
-
7: { model: 'A', revision: '2.0', memory: '256MB', manufacturer: 'Egoman' },
|
|
68
|
-
8: { model: 'A', revision: '2.0', memory: '256MB', manufacturer: 'Sony UK' },
|
|
69
|
-
9: { model: 'A', revision: '2.0', memory: '256MB', manufacturer: 'Qisda' },
|
|
70
|
-
13: { model: 'B', revision: '2.0', memory: '512MB', manufacturer: 'Egoman' },
|
|
71
|
-
14: { model: 'B', revision: '2.0', memory: '512MB', manufacturer: 'Sony UK' },
|
|
72
|
-
15: { model: 'B', revision: '2.0', memory: '512MB', manufacturer: 'Egoman' },
|
|
73
|
-
16: { model: 'B+', revision: '1.2', memory: '512MB', manufacturer: 'Sony UK' },
|
|
74
|
-
17: { model: 'CM1', revision: '1.0', memory: '512MB', manufacturer: 'Sony UK' },
|
|
75
|
-
18: { model: 'A+', revision: '1.1', memory: '256MB', manufacturer: 'Sony UK' },
|
|
76
|
-
19: { model: 'B+', revision: '1.2', memory: '512MB', manufacturer: 'Embest' },
|
|
77
|
-
20: { model: 'CM1', revision: '1.0', memory: '512MB', manufacturer: 'Embest' },
|
|
78
|
-
21: { model: 'A+', revision: '1.1', memory: '256MB/512MB', manufacturer: 'Embest' }
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// See: https://en.wikipedia.org/wiki/MacOS_version_history
|
|
83
|
-
const macOsInfo = {
|
|
84
|
-
versionNames: {
|
|
85
|
-
'10.0': 'Cheetah',
|
|
86
|
-
10.1: 'Puma',
|
|
87
|
-
10.2: 'Jaguar',
|
|
88
|
-
10.3: 'Panther',
|
|
89
|
-
10.4: 'Tiger',
|
|
90
|
-
10.5: 'Leopard',
|
|
91
|
-
10.6: 'Snow Leopard',
|
|
92
|
-
10.7: 'Lion',
|
|
93
|
-
10.8: 'Mountain Lion',
|
|
94
|
-
10.9: 'Mavericks',
|
|
95
|
-
'10.10': 'Yosemite',
|
|
96
|
-
10.11: 'El Capitan',
|
|
97
|
-
10.12: 'Sierra',
|
|
98
|
-
10.13: 'High Sierra',
|
|
99
|
-
10.14: 'Mojave',
|
|
100
|
-
10.15: 'Catalina',
|
|
101
|
-
11: 'Big Sur',
|
|
102
|
-
12: 'Monterey',
|
|
103
|
-
13: 'Ventura'
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/** System information.
|
|
108
|
-
* @extends EventEmitter
|
|
109
|
-
*/
|
|
110
|
-
class SystemInfo extends events.EventEmitter {
|
|
111
|
-
/** Extract Raspberry Pi serial number and hardware revision info from the
|
|
112
|
-
* contents of `/proc/cpuinfo`.
|
|
113
|
-
* @param {string} cpuInfo - The contents of `/proc/cpuinfo`.
|
|
114
|
-
* @return {object} - The extracted info.
|
|
115
|
-
*/
|
|
116
|
-
static parseRpiCpuInfo (cpuInfo) {
|
|
117
|
-
let a = /Serial\s*: ([0-9a-f]{16})/.exec(cpuInfo)
|
|
118
|
-
if (a == null || a.length < 2) {
|
|
119
|
-
return null
|
|
120
|
-
}
|
|
121
|
-
const id = a[1].toUpperCase()
|
|
122
|
-
a = /Revision\s*: ([0-9a-f]{4,})/.exec(cpuInfo)
|
|
123
|
-
if (a == null || a.length < 2) {
|
|
124
|
-
return null
|
|
125
|
-
}
|
|
126
|
-
const revision = parseInt(a[1], 16) & 0x00FFFFFF
|
|
127
|
-
let gpioMask, manufacturer, memory, model, modelRevision, processor
|
|
128
|
-
if ((revision & 0x00800000) !== 0) { // New revision scheme.
|
|
129
|
-
manufacturer = rpiInfo.manufacturers[(revision & 0x000F0000) >> 16]
|
|
130
|
-
memory = rpiInfo.memorySizes[(revision & 0x00700000) >> 20]
|
|
131
|
-
model = rpiInfo.models[(revision & 0x00000FF0) >> 4]
|
|
132
|
-
modelRevision = '1.' + ((revision & 0x0000000F) >> 0).toString()
|
|
133
|
-
processor = rpiInfo.processors[(revision & 0x0000F000) >> 12]
|
|
134
|
-
} else if (rpiInfo.oldRevisions[revision] != null) { // Old incremental revisions.
|
|
135
|
-
manufacturer = rpiInfo.oldRevisions[revision].manufacturer
|
|
136
|
-
memory = rpiInfo.oldRevisions[revision].memory
|
|
137
|
-
model = rpiInfo.oldRevisions[revision].model
|
|
138
|
-
modelRevision = rpiInfo.oldRevisions[revision].revision
|
|
139
|
-
processor = 'BCM2835'
|
|
140
|
-
}
|
|
141
|
-
if (model != null && model.startsWith('CM')) {
|
|
142
|
-
// Compute module
|
|
143
|
-
gpioMask = 0xFFFFFFFF // 0-31
|
|
144
|
-
} else if (revision >= 16) {
|
|
145
|
-
// Type 3
|
|
146
|
-
gpioMask = 0x0FFFFFFC // 2-27
|
|
147
|
-
} else if (revision >= 4) {
|
|
148
|
-
// Type 2
|
|
149
|
-
gpioMask = 0xFBC6CF9C // 2-4, 7-11, 14-15, 17-18, 22-25, 27-31
|
|
150
|
-
} else {
|
|
151
|
-
// Type 1
|
|
152
|
-
gpioMask = 0x03E6CF93 // 0-1, 4, 7-11, 14-15, 17-18, 21-25
|
|
153
|
-
}
|
|
154
|
-
return {
|
|
155
|
-
gpioMask,
|
|
156
|
-
gpioMaskSerial: (1 << 15) | (1 << 14),
|
|
157
|
-
id,
|
|
158
|
-
isRpi: true,
|
|
159
|
-
manufacturer,
|
|
160
|
-
memory,
|
|
161
|
-
model,
|
|
162
|
-
modelRevision,
|
|
163
|
-
prettyName: [
|
|
164
|
-
'Raspberry Pi', model, modelRevision, '(' + memory + ')'
|
|
165
|
-
].join(' '),
|
|
166
|
-
powerLed: !(['A', 'B', 'Zero', 'Zero W', 'Zero 2 W'].includes(model)),
|
|
167
|
-
processor,
|
|
168
|
-
revision: homebridgeLib.toHexString(revision, 6),
|
|
169
|
-
usbPower: ['B+', '2B', '3B', '3B+'].includes(model)
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/** Initialise SystemInfo instance.
|
|
174
|
-
*/
|
|
175
|
-
async init () {
|
|
176
|
-
switch (process.platform) {
|
|
177
|
-
case 'linux':
|
|
178
|
-
if (await this.existsFile('/etc/synoinfo.conf')) {
|
|
179
|
-
try {
|
|
180
|
-
this.osInfo = await this.getDsmInfo()
|
|
181
|
-
} catch (error) { this.emit('error', error) }
|
|
182
|
-
try {
|
|
183
|
-
this.hwInfo = await this.getSynoInfo()
|
|
184
|
-
} catch (error) { this.emit('error', error) }
|
|
185
|
-
} else {
|
|
186
|
-
try {
|
|
187
|
-
this.osInfo = await this.getPiOsInfo()
|
|
188
|
-
} catch (error) { this.emit('error', error) }
|
|
189
|
-
if (['arm', 'arm64'].includes(process.arch)) {
|
|
190
|
-
try {
|
|
191
|
-
this.hwInfo = await this.getRpiInfo()
|
|
192
|
-
} catch (error) { this.emit('error', error) }
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
break
|
|
196
|
-
case 'darwin':
|
|
197
|
-
try {
|
|
198
|
-
this.osInfo = await this.getMacOsInfo()
|
|
199
|
-
} catch (error) { this.emit('error', error) }
|
|
200
|
-
try {
|
|
201
|
-
this.hwInfo = await this.getMacInfo()
|
|
202
|
-
} catch (error) { this.emit('error', error) }
|
|
203
|
-
break
|
|
204
|
-
default:
|
|
205
|
-
break
|
|
206
|
-
}
|
|
207
|
-
if (this.osInfo == null) {
|
|
208
|
-
this.osInfo = {
|
|
209
|
-
name: process.platform,
|
|
210
|
-
platform: process.platform,
|
|
211
|
-
prettyName: process.platform
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
if (this.hwInfo == null) {
|
|
215
|
-
this.hwInfo = {
|
|
216
|
-
nCores: os.cpus().length,
|
|
217
|
-
prettyName: process.arch,
|
|
218
|
-
processor: process.arch
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
this.platform = this.osInfo.platform
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/** Extract serial number and hardware revision info from `/proc/cpuinfo`.
|
|
225
|
-
* @return {object} - The extracted info.
|
|
226
|
-
*/
|
|
227
|
-
async getRpiInfo () {
|
|
228
|
-
const cpuInfo = await this.readTextFile('/proc/cpuinfo')
|
|
229
|
-
return SystemInfo.parseRpiCpuInfo(cpuInfo)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/** Extract OS info from /etc/os-release.
|
|
233
|
-
* @return {object} - The extracted info.
|
|
234
|
-
*/
|
|
235
|
-
async getPiOsInfo () {
|
|
236
|
-
let name, platform, prettyName, version, versionName
|
|
237
|
-
const text = await this.readTextFile('/etc/os-release')
|
|
238
|
-
const lines = text.replace(/"/g, '').split('\n')
|
|
239
|
-
for (const line of lines) {
|
|
240
|
-
const fields = line.split('=')
|
|
241
|
-
if (fields.length === 2) {
|
|
242
|
-
switch (fields[0]) {
|
|
243
|
-
case 'ID':
|
|
244
|
-
platform = fields[1] // e.g. 'raspbian'
|
|
245
|
-
break
|
|
246
|
-
case 'NAME':
|
|
247
|
-
name = fields[1] // e.g. 'Raspbian GNU/Linux'
|
|
248
|
-
break
|
|
249
|
-
case 'PRETTY_NAME':
|
|
250
|
-
prettyName = fields[1] // e.g. 'Raspbian GNU/Linux 11 (bullseye)'
|
|
251
|
-
break
|
|
252
|
-
case 'VERSION_CODENAME':
|
|
253
|
-
versionName = fields[1] // e.g. 'bullseye'
|
|
254
|
-
break
|
|
255
|
-
case 'VERSION_ID':
|
|
256
|
-
version = fields[1] // e.g. '11'
|
|
257
|
-
break
|
|
258
|
-
default:
|
|
259
|
-
break
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
return { name, platform, prettyName, version, versionName }
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/** Extract Apple Mac hardware info from `system_profiler` command.
|
|
267
|
-
* @return {object} - The extracted info.
|
|
268
|
-
*/
|
|
269
|
-
async getMacInfo () {
|
|
270
|
-
let id, memory, model, nCores, prettyName, processor, revision
|
|
271
|
-
let text = await this.exec('system_profiler', 'SPHardwareDataType')
|
|
272
|
-
const lines = text.split('\n')
|
|
273
|
-
for (const line of lines) {
|
|
274
|
-
const fields = line.split(': ')
|
|
275
|
-
if (fields.length === 2) {
|
|
276
|
-
switch (fields[0].trim()) {
|
|
277
|
-
case 'Memory':
|
|
278
|
-
memory = fields[1].replace(/ /g, '')
|
|
279
|
-
break
|
|
280
|
-
case 'Model Identifier':
|
|
281
|
-
revision = fields[1]
|
|
282
|
-
break
|
|
283
|
-
case 'Model Name':
|
|
284
|
-
model = fields[1]
|
|
285
|
-
break
|
|
286
|
-
case 'Chip':
|
|
287
|
-
case 'Processor Name':
|
|
288
|
-
processor = fields[1]
|
|
289
|
-
break
|
|
290
|
-
case 'Serial Number (system)':
|
|
291
|
-
id = fields[1]
|
|
292
|
-
break
|
|
293
|
-
case 'Total Number of Cores':
|
|
294
|
-
nCores = fields[1].split(' ')[0]
|
|
295
|
-
break
|
|
296
|
-
default:
|
|
297
|
-
break
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
try {
|
|
302
|
-
if (process.arch === 'x64') { // Intel
|
|
303
|
-
text = await this.exec(
|
|
304
|
-
'plutil', '-p',
|
|
305
|
-
process.env.HOME + '/Library/Preferences/com.apple.SystemProfiler.plist'
|
|
306
|
-
)
|
|
307
|
-
const regexp = RegExp(
|
|
308
|
-
'"(' + id.slice(-4) + '|' + id.slice(-3) + ').*" => "(.*)"'
|
|
309
|
-
)
|
|
310
|
-
const a = regexp.exec(text)
|
|
311
|
-
if (a != null) {
|
|
312
|
-
prettyName = a[2]
|
|
313
|
-
}
|
|
314
|
-
} else { // Apple silicon
|
|
315
|
-
text = await this.execShell('ioreg -l | grep product-description')
|
|
316
|
-
const a = /"product-description" = <"([^"]*)">/.exec(text)
|
|
317
|
-
if (a != null) {
|
|
318
|
-
prettyName = a[1]
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
} catch (error) {
|
|
322
|
-
this.emit('error', error)
|
|
323
|
-
}
|
|
324
|
-
return {
|
|
325
|
-
id,
|
|
326
|
-
isMac: true,
|
|
327
|
-
manufacturer: 'Apple Inc.',
|
|
328
|
-
memory,
|
|
329
|
-
model,
|
|
330
|
-
nCores,
|
|
331
|
-
prettyName: prettyName || model,
|
|
332
|
-
processor,
|
|
333
|
-
revision
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/** Extract macOS info from `sw_vers` command.
|
|
338
|
-
* @return {object} - The extracted info.
|
|
339
|
-
*/
|
|
340
|
-
async getMacOsInfo () {
|
|
341
|
-
let name, version, build
|
|
342
|
-
const text = await this.exec('sw_vers')
|
|
343
|
-
const lines = text.split('\n')
|
|
344
|
-
for (const line of lines) {
|
|
345
|
-
const fields = line.split(':')
|
|
346
|
-
if (fields.length === 2) {
|
|
347
|
-
switch (fields[0]) {
|
|
348
|
-
case 'ProductName': // e.g. 'macOS' or 'Mac OS X'
|
|
349
|
-
name = fields[1].trim()
|
|
350
|
-
break
|
|
351
|
-
case 'ProductVersion': // e.g. '12.0.1' or '12.1'
|
|
352
|
-
version = fields[1].trim()
|
|
353
|
-
if (version.split('.').length === 2) {
|
|
354
|
-
version += '.0'
|
|
355
|
-
}
|
|
356
|
-
break
|
|
357
|
-
case 'BuildVersion': // e.g. '21A559'
|
|
358
|
-
build = fields[1].trim()
|
|
359
|
-
break
|
|
360
|
-
default:
|
|
361
|
-
break
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
let v = semver.major(version)
|
|
366
|
-
if (v === 10) {
|
|
367
|
-
v += '.' + semver.minor(version)
|
|
368
|
-
}
|
|
369
|
-
const versionName = macOsInfo.versionNames[v] // e.g. 'Monterey'
|
|
370
|
-
return {
|
|
371
|
-
build,
|
|
372
|
-
catalina: semver.gte(version, '10.15.0'),
|
|
373
|
-
name,
|
|
374
|
-
platform: process.platform,
|
|
375
|
-
prettyName: [name, versionName, version, '(' + build + ')'].join(' '),
|
|
376
|
-
version,
|
|
377
|
-
versionName
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/** Extract Synology info from `/etc/synoinfo.conf`
|
|
382
|
-
* @return {object} - The extracted info.
|
|
383
|
-
*/
|
|
384
|
-
async getSynoInfo () {
|
|
385
|
-
let device = ''
|
|
386
|
-
let id
|
|
387
|
-
let model = ''
|
|
388
|
-
const text = await this.readTextFile('/etc/synoinfo.conf')
|
|
389
|
-
const lines = text.replace(/"/g, '').split('\n')
|
|
390
|
-
for (const line of lines) {
|
|
391
|
-
const fields = line.split('=')
|
|
392
|
-
if (fields.length === 2) {
|
|
393
|
-
switch (fields[0].trim()) {
|
|
394
|
-
case 'pushservice_dsserial':
|
|
395
|
-
id = fields[1] // e.g 1970PDN255608
|
|
396
|
-
break
|
|
397
|
-
case 'upnpdevicetype':
|
|
398
|
-
device = fields[1] // e.g. DiskStation
|
|
399
|
-
break
|
|
400
|
-
case 'upnpmodelname':
|
|
401
|
-
model = fields[1] // e.g. DS918+
|
|
402
|
-
break
|
|
403
|
-
default:
|
|
404
|
-
break
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
return {
|
|
409
|
-
id,
|
|
410
|
-
manufacturer: 'Synology',
|
|
411
|
-
model: [device, model].join(' '),
|
|
412
|
-
prettyName: ['Synology', device, model].join(' ')
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
/** Extract DSM info from `/etc/VERSION`.
|
|
417
|
-
* @return {object} - The extracted info.
|
|
418
|
-
*/
|
|
419
|
-
async getDsmInfo () {
|
|
420
|
-
let build, prettyName, update, version
|
|
421
|
-
const text = await this.readTextFile('/etc/VERSION')
|
|
422
|
-
const lines = text.replace(/"/g, '').split('\n')
|
|
423
|
-
for (const line of lines) {
|
|
424
|
-
const fields = line.split('=')
|
|
425
|
-
if (fields.length === 2) {
|
|
426
|
-
switch (fields[0].trim()) {
|
|
427
|
-
case 'buildnumber':
|
|
428
|
-
build = fields[1] // e.g. 42661
|
|
429
|
-
break
|
|
430
|
-
case 'productversion':
|
|
431
|
-
version = fields[1] // e.g. 7.1
|
|
432
|
-
break
|
|
433
|
-
case 'smallfixnumber':
|
|
434
|
-
update = fields[1] // e.g. 3
|
|
435
|
-
break
|
|
436
|
-
default:
|
|
437
|
-
break
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
prettyName = 'DSM'
|
|
442
|
-
if (version != null) {
|
|
443
|
-
prettyName += ' ' + version
|
|
444
|
-
if (build != null) {
|
|
445
|
-
prettyName += '-' + build
|
|
446
|
-
}
|
|
447
|
-
if (update != null) {
|
|
448
|
-
prettyName += ' Update ' + update
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
return {
|
|
452
|
-
build,
|
|
453
|
-
prettyName,
|
|
454
|
-
update,
|
|
455
|
-
version
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
/** Execute a command on the local machine.
|
|
460
|
-
* @param {string} command - The command.
|
|
461
|
-
* @param {...string} ...args - The command parameters.
|
|
462
|
-
* @return {string} - The output of the command.
|
|
463
|
-
*/
|
|
464
|
-
async exec (command, ...args) {
|
|
465
|
-
return new Promise((resolve, reject) => {
|
|
466
|
-
/** Emitted when a command is executed.
|
|
467
|
-
* @event SystemInfo#exec
|
|
468
|
-
* @param {string} command - The command.
|
|
469
|
-
*/
|
|
470
|
-
this.emit('exec', command + ' ' + args.join(' '))
|
|
471
|
-
execFile(command, args, null, (error, stdout, stderr) => {
|
|
472
|
-
if (error != null) {
|
|
473
|
-
reject(error)
|
|
474
|
-
}
|
|
475
|
-
resolve(stdout)
|
|
476
|
-
})
|
|
477
|
-
})
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/** Execute a shell command on the local machine.
|
|
481
|
-
* @param {string} command - The command.
|
|
482
|
-
* @return {string} - The output of the command.
|
|
483
|
-
*/
|
|
484
|
-
async execShell (command) {
|
|
485
|
-
return new Promise((resolve, reject) => {
|
|
486
|
-
this.emit('exec', command)
|
|
487
|
-
exec(command, (error, stdout, stderr) => {
|
|
488
|
-
if (error != null) {
|
|
489
|
-
reject(error)
|
|
490
|
-
}
|
|
491
|
-
resolve(stdout)
|
|
492
|
-
})
|
|
493
|
-
})
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
/** Check if file exists.
|
|
497
|
-
* @param {string} fileName - The file name.
|
|
498
|
-
* @return {bool} - True iff file exists,
|
|
499
|
-
*/
|
|
500
|
-
async existsFile (fileName) {
|
|
501
|
-
try {
|
|
502
|
-
await fs.access(fileName)
|
|
503
|
-
return true
|
|
504
|
-
} catch (error) {}
|
|
505
|
-
return false
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/** Read a text file.
|
|
509
|
-
* @param {string} fileName - The file name.
|
|
510
|
-
* @return {string} - The contents of the file.
|
|
511
|
-
*/
|
|
512
|
-
async readTextFile (fileName) {
|
|
513
|
-
/** Emitted when a file is read.
|
|
514
|
-
* @event SystemInfo#readFile
|
|
515
|
-
* @param {string} fileName - The file name.
|
|
516
|
-
*/
|
|
517
|
-
this.emit('readFile', fileName)
|
|
518
|
-
return fs.readFile(fileName, 'utf8')
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
module.exports = SystemInfo
|