sysiddr5 1.0.1-beta-3
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.
Potentially problematic release.
This version of sysiddr5 might be problematic. Click here for more details.
- package/LICENSE +20 -0
- package/README.md +885 -0
- package/lib/audio.js +222 -0
- package/lib/battery.js +308 -0
- package/lib/bluetooth.js +229 -0
- package/lib/cli.js +31 -0
- package/lib/cpu.js +1704 -0
- package/lib/docker.js +757 -0
- package/lib/dockerSocket.js +327 -0
- package/lib/filesystem.js +1495 -0
- package/lib/graphics.js +1103 -0
- package/lib/index.d.ts +1028 -0
- package/lib/index.js +504 -0
- package/lib/internet.js +236 -0
- package/lib/memory.js +559 -0
- package/lib/network.js +1779 -0
- package/lib/osinfo.js +1167 -0
- package/lib/printer.js +210 -0
- package/lib/processes.js +1289 -0
- package/lib/system.js +720 -0
- package/lib/usb.js +274 -0
- package/lib/users.js +363 -0
- package/lib/util.js +1303 -0
- package/lib/virtualbox.js +107 -0
- package/lib/wifi.js +744 -0
- package/package.json +90 -0
package/lib/graphics.js
ADDED
@@ -0,0 +1,1103 @@
|
|
1
|
+
'use strict';
|
2
|
+
// @ts-check
|
3
|
+
// ==================================================================================
|
4
|
+
// graphics.js
|
5
|
+
// ----------------------------------------------------------------------------------
|
6
|
+
// Description: System Information - library
|
7
|
+
// for Node.js
|
8
|
+
// Copyright: (c) 2014 - 2023
|
9
|
+
// Author: Sebastian Hildebrandt
|
10
|
+
// ----------------------------------------------------------------------------------
|
11
|
+
// License: MIT
|
12
|
+
// ==================================================================================
|
13
|
+
// 7. Graphics (controller, display)
|
14
|
+
// ----------------------------------------------------------------------------------
|
15
|
+
|
16
|
+
const fs = require('fs');
|
17
|
+
const exec = require('child_process').exec;
|
18
|
+
const execSync = require('child_process').execSync;
|
19
|
+
const util = require('./util');
|
20
|
+
|
21
|
+
let _platform = process.platform;
|
22
|
+
let _nvidiaSmiPath = '';
|
23
|
+
|
24
|
+
const _linux = (_platform === 'linux' || _platform === 'android');
|
25
|
+
const _darwin = (_platform === 'darwin');
|
26
|
+
const _windows = (_platform === 'win32');
|
27
|
+
const _freebsd = (_platform === 'freebsd');
|
28
|
+
const _openbsd = (_platform === 'openbsd');
|
29
|
+
const _netbsd = (_platform === 'netbsd');
|
30
|
+
const _sunos = (_platform === 'sunos');
|
31
|
+
|
32
|
+
let _resolutionX = 0;
|
33
|
+
let _resolutionY = 0;
|
34
|
+
let _pixelDepth = 0;
|
35
|
+
let _refreshRate = 0;
|
36
|
+
|
37
|
+
const videoTypes = {
|
38
|
+
'-2': 'UNINITIALIZED',
|
39
|
+
'-1': 'OTHER',
|
40
|
+
'0': 'HD15',
|
41
|
+
'1': 'SVIDEO',
|
42
|
+
'2': 'Composite video',
|
43
|
+
'3': 'Component video',
|
44
|
+
'4': 'DVI',
|
45
|
+
'5': 'HDMI',
|
46
|
+
'6': 'LVDS',
|
47
|
+
'8': 'D_JPN',
|
48
|
+
'9': 'SDI',
|
49
|
+
'10': 'DP',
|
50
|
+
'11': 'DP embedded',
|
51
|
+
'12': 'UDI',
|
52
|
+
'13': 'UDI embedded',
|
53
|
+
'14': 'SDTVDONGLE',
|
54
|
+
'15': 'MIRACAST',
|
55
|
+
'2147483648': 'INTERNAL'
|
56
|
+
};
|
57
|
+
|
58
|
+
function getVendorFromModel(model) {
|
59
|
+
const manufacturers = [
|
60
|
+
{ pattern: '^LG.+', manufacturer: 'LG' },
|
61
|
+
{ pattern: '^BENQ.+', manufacturer: 'BenQ' },
|
62
|
+
{ pattern: '^ASUS.+', manufacturer: 'Asus' },
|
63
|
+
{ pattern: '^DELL.+', manufacturer: 'Dell' },
|
64
|
+
{ pattern: '^SAMSUNG.+', manufacturer: 'Samsung' },
|
65
|
+
{ pattern: '^VIEWSON.+', manufacturer: 'ViewSonic' },
|
66
|
+
{ pattern: '^SONY.+', manufacturer: 'Sony' },
|
67
|
+
{ pattern: '^ACER.+', manufacturer: 'Acer' },
|
68
|
+
{ pattern: '^AOC.+', manufacturer: 'AOC Monitors' },
|
69
|
+
{ pattern: '^HP.+', manufacturer: 'HP' },
|
70
|
+
{ pattern: '^EIZO.?', manufacturer: 'Eizo' },
|
71
|
+
{ pattern: '^PHILIPS.?', manufacturer: 'Philips' },
|
72
|
+
{ pattern: '^IIYAMA.?', manufacturer: 'Iiyama' },
|
73
|
+
{ pattern: '^SHARP.?', manufacturer: 'Sharp' },
|
74
|
+
{ pattern: '^NEC.?', manufacturer: 'NEC' },
|
75
|
+
{ pattern: '^LENOVO.?', manufacturer: 'Lenovo' },
|
76
|
+
{ pattern: 'COMPAQ.?', manufacturer: 'Compaq' },
|
77
|
+
{ pattern: 'APPLE.?', manufacturer: 'Apple' },
|
78
|
+
{ pattern: 'INTEL.?', manufacturer: 'Intel' },
|
79
|
+
{ pattern: 'AMD.?', manufacturer: 'AMD' },
|
80
|
+
{ pattern: 'NVIDIA.?', manufacturer: 'NVDIA' },
|
81
|
+
];
|
82
|
+
|
83
|
+
let result = '';
|
84
|
+
if (model) {
|
85
|
+
model = model.toUpperCase();
|
86
|
+
manufacturers.forEach((manufacturer) => {
|
87
|
+
const re = RegExp(manufacturer.pattern);
|
88
|
+
if (re.test(model)) { result = manufacturer.manufacturer; }
|
89
|
+
});
|
90
|
+
}
|
91
|
+
return result;
|
92
|
+
}
|
93
|
+
|
94
|
+
function getVendorFromId(id) {
|
95
|
+
const vendors = {
|
96
|
+
'610': 'Apple',
|
97
|
+
'1e6d': 'LG',
|
98
|
+
'10ac': 'DELL',
|
99
|
+
'4dd9': 'Sony',
|
100
|
+
'38a3': 'NEC',
|
101
|
+
};
|
102
|
+
return vendors[id] || '';
|
103
|
+
}
|
104
|
+
|
105
|
+
function vendorToId(str) {
|
106
|
+
let result = '';
|
107
|
+
str = (str || '').toLowerCase();
|
108
|
+
if (str.indexOf('apple') >= 0) { result = '0x05ac'; }
|
109
|
+
else if (str.indexOf('nvidia') >= 0) { result = '0x10de'; }
|
110
|
+
else if (str.indexOf('intel') >= 0) { result = '0x8086'; }
|
111
|
+
else if (str.indexOf('ati') >= 0 || str.indexOf('amd') >= 0) { result = '0x1002'; }
|
112
|
+
|
113
|
+
return result;
|
114
|
+
}
|
115
|
+
|
116
|
+
function getMetalVersion(id) {
|
117
|
+
const families = {
|
118
|
+
'spdisplays_mtlgpufamilymac1': 'mac1',
|
119
|
+
'spdisplays_mtlgpufamilymac2': 'mac2',
|
120
|
+
'spdisplays_mtlgpufamilyapple1': 'apple1',
|
121
|
+
'spdisplays_mtlgpufamilyapple2': 'apple2',
|
122
|
+
'spdisplays_mtlgpufamilyapple3': 'apple3',
|
123
|
+
'spdisplays_mtlgpufamilyapple4': 'apple4',
|
124
|
+
'spdisplays_mtlgpufamilyapple5': 'apple5',
|
125
|
+
'spdisplays_mtlgpufamilyapple6': 'apple6',
|
126
|
+
'spdisplays_mtlgpufamilyapple7': 'apple7',
|
127
|
+
'spdisplays_metalfeaturesetfamily11': 'family1_v1',
|
128
|
+
'spdisplays_metalfeaturesetfamily12': 'family1_v2',
|
129
|
+
'spdisplays_metalfeaturesetfamily13': 'family1_v3',
|
130
|
+
'spdisplays_metalfeaturesetfamily14': 'family1_v4',
|
131
|
+
'spdisplays_metalfeaturesetfamily21': 'family2_v1'
|
132
|
+
};
|
133
|
+
return families[id] || '';
|
134
|
+
}
|
135
|
+
|
136
|
+
function graphics(callback) {
|
137
|
+
|
138
|
+
function parseLinesDarwin(graphicsArr) {
|
139
|
+
const res = {
|
140
|
+
controllers: [],
|
141
|
+
displays: []
|
142
|
+
};
|
143
|
+
try {
|
144
|
+
graphicsArr.forEach(function (item) {
|
145
|
+
// controllers
|
146
|
+
const bus = ((item.sppci_bus || '').indexOf('builtin') > -1 ? 'Built-In' : ((item.sppci_bus || '').indexOf('pcie') > -1 ? 'PCIe' : ''));
|
147
|
+
const vram = (parseInt((item.spdisplays_vram || ''), 10) || 0) * (((item.spdisplays_vram || '').indexOf('GB') > -1) ? 1024 : 1);
|
148
|
+
const vramDyn = (parseInt((item.spdisplays_vram_shared || ''), 10) || 0) * (((item.spdisplays_vram_shared || '').indexOf('GB') > -1) ? 1024 : 1);
|
149
|
+
let metalVersion = getMetalVersion(item.spdisplays_metal || item.spdisplays_metalfamily || '');
|
150
|
+
res.controllers.push({
|
151
|
+
vendor: getVendorFromModel(item.spdisplays_vendor || '') || item.spdisplays_vendor || '',
|
152
|
+
model: item.sppci_model || '',
|
153
|
+
bus,
|
154
|
+
vramDynamic: bus === 'Built-In',
|
155
|
+
vram: vram || vramDyn || null,
|
156
|
+
deviceId: item['spdisplays_device-id'] || '',
|
157
|
+
vendorId: item['spdisplays_vendor-id'] || vendorToId((item['spdisplays_vendor'] || '') + (item.sppci_model || '')),
|
158
|
+
external: (item.sppci_device_type === 'spdisplays_egpu'),
|
159
|
+
cores: item['sppci_cores'] || null,
|
160
|
+
metalVersion
|
161
|
+
});
|
162
|
+
|
163
|
+
// displays
|
164
|
+
if (item.spdisplays_ndrvs && item.spdisplays_ndrvs.length) {
|
165
|
+
item.spdisplays_ndrvs.forEach(function (displayItem) {
|
166
|
+
const connectionType = displayItem['spdisplays_connection_type'] || '';
|
167
|
+
const currentResolutionParts = (displayItem['_spdisplays_resolution'] || '').split('@');
|
168
|
+
const currentResolution = currentResolutionParts[0].split('x');
|
169
|
+
const pixelParts = (displayItem['_spdisplays_pixels'] || '').split('x');
|
170
|
+
const pixelDepthString = displayItem['spdisplays_depth'] || '';
|
171
|
+
const serial = displayItem['_spdisplays_display-serial-number'] || displayItem['_spdisplays_display-serial-number2'] || null;
|
172
|
+
res.displays.push({
|
173
|
+
vendor: getVendorFromId(displayItem['_spdisplays_display-vendor-id'] || '') || getVendorFromModel(displayItem['_name'] || ''),
|
174
|
+
vendorId: displayItem['_spdisplays_display-vendor-id'] || '',
|
175
|
+
model: displayItem['_name'] || '',
|
176
|
+
productionYear: displayItem['_spdisplays_display-year'] || null,
|
177
|
+
serial: serial !== '0' ? serial : null,
|
178
|
+
displayId: displayItem['_spdisplays_displayID'] || null,
|
179
|
+
main: displayItem['spdisplays_main'] ? displayItem['spdisplays_main'] === 'spdisplays_yes' : false,
|
180
|
+
builtin: (displayItem['spdisplays_display_type'] || '').indexOf('built-in') > -1,
|
181
|
+
connection: ((connectionType.indexOf('_internal') > -1) ? 'Internal' : ((connectionType.indexOf('_displayport') > -1) ? 'Display Port' : ((connectionType.indexOf('_hdmi') > -1) ? 'HDMI' : null))),
|
182
|
+
sizeX: null,
|
183
|
+
sizeY: null,
|
184
|
+
pixelDepth: (pixelDepthString === 'CGSThirtyBitColor' ? 30 : (pixelDepthString === 'CGSThirtytwoBitColor' ? 32 : (pixelDepthString === 'CGSTwentyfourBitColor' ? 24 : null))),
|
185
|
+
resolutionX: pixelParts.length > 1 ? parseInt(pixelParts[0], 10) : null,
|
186
|
+
resolutionY: pixelParts.length > 1 ? parseInt(pixelParts[1], 10) : null,
|
187
|
+
currentResX: currentResolution.length > 1 ? parseInt(currentResolution[0], 10) : null,
|
188
|
+
currentResY: currentResolution.length > 1 ? parseInt(currentResolution[1], 10) : null,
|
189
|
+
positionX: 0,
|
190
|
+
positionY: 0,
|
191
|
+
currentRefreshRate: currentResolutionParts.length > 1 ? parseInt(currentResolutionParts[1], 10) : null,
|
192
|
+
|
193
|
+
});
|
194
|
+
});
|
195
|
+
}
|
196
|
+
});
|
197
|
+
return res;
|
198
|
+
} catch (e) {
|
199
|
+
return res;
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
function parseLinesLinuxControllers(lines) {
|
204
|
+
let controllers = [];
|
205
|
+
let currentController = {
|
206
|
+
vendor: '',
|
207
|
+
model: '',
|
208
|
+
bus: '',
|
209
|
+
busAddress: '',
|
210
|
+
vram: null,
|
211
|
+
vramDynamic: false,
|
212
|
+
pciID: ''
|
213
|
+
};
|
214
|
+
let isGraphicsController = false;
|
215
|
+
// PCI bus IDs
|
216
|
+
let pciIDs = [];
|
217
|
+
try {
|
218
|
+
pciIDs = execSync('export LC_ALL=C; dmidecode -t 9 2>/dev/null; unset LC_ALL | grep "Bus Address: "').toString().split('\n');
|
219
|
+
for (let i = 0; i < pciIDs.length; i++) {
|
220
|
+
pciIDs[i] = pciIDs[i].replace('Bus Address:', '').replace('0000:', '').trim();
|
221
|
+
}
|
222
|
+
pciIDs = pciIDs.filter(function (el) {
|
223
|
+
return el != null && el;
|
224
|
+
});
|
225
|
+
} catch (e) {
|
226
|
+
util.noop();
|
227
|
+
}
|
228
|
+
lines.forEach((line) => {
|
229
|
+
if ('' !== line.trim()) {
|
230
|
+
if (' ' !== line[0] && '\t' !== line[0]) { // first line of new entry
|
231
|
+
let isExternal = (pciIDs.indexOf(line.split(' ')[0]) >= 0);
|
232
|
+
let vgapos = line.toLowerCase().indexOf(' vga ');
|
233
|
+
let _3dcontrollerpos = line.toLowerCase().indexOf('3d controller');
|
234
|
+
if (vgapos !== -1 || _3dcontrollerpos !== -1) { // VGA
|
235
|
+
if (_3dcontrollerpos !== -1 && vgapos === -1) {
|
236
|
+
vgapos = _3dcontrollerpos;
|
237
|
+
}
|
238
|
+
if (currentController.vendor || currentController.model || currentController.bus || currentController.vram !== null || currentController.vramDynamic) { // already a controller found
|
239
|
+
controllers.push(currentController);
|
240
|
+
currentController = {
|
241
|
+
vendor: '',
|
242
|
+
model: '',
|
243
|
+
bus: '',
|
244
|
+
busAddress: '',
|
245
|
+
vram: null,
|
246
|
+
vramDynamic: false,
|
247
|
+
};
|
248
|
+
}
|
249
|
+
|
250
|
+
const pciIDCandidate = line.split(' ')[0];
|
251
|
+
if (/[\da-fA-F]{2}:[\da-fA-F]{2}\.[\da-fA-F]/.test(pciIDCandidate)) {
|
252
|
+
currentController.busAddress = pciIDCandidate;
|
253
|
+
}
|
254
|
+
isGraphicsController = true;
|
255
|
+
let endpos = line.search(/\[[0-9a-f]{4}:[0-9a-f]{4}]|$/);
|
256
|
+
let parts = line.substr(vgapos, endpos - vgapos).split(':');
|
257
|
+
currentController.busAddress = line.substr(0, vgapos).trim();
|
258
|
+
if (parts.length > 1) {
|
259
|
+
parts[1] = parts[1].trim();
|
260
|
+
if (parts[1].toLowerCase().indexOf('corporation') >= 0) {
|
261
|
+
currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf('corporation') + 11).trim();
|
262
|
+
currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf('corporation') + 11, 200).trim().split('(')[0];
|
263
|
+
currentController.bus = (pciIDs.length > 0 && isExternal) ? 'PCIe' : 'Onboard';
|
264
|
+
currentController.vram = null;
|
265
|
+
currentController.vramDynamic = false;
|
266
|
+
} else if (parts[1].toLowerCase().indexOf(' inc.') >= 0) {
|
267
|
+
if ((parts[1].match(/]/g) || []).length > 1) {
|
268
|
+
currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(']') + 1).trim();
|
269
|
+
currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf(']') + 1, 200).trim().split('(')[0].trim();
|
270
|
+
} else {
|
271
|
+
currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(' inc.') + 5).trim();
|
272
|
+
currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf(' inc.') + 5, 200).trim().split('(')[0].trim();
|
273
|
+
}
|
274
|
+
currentController.bus = (pciIDs.length > 0 && isExternal) ? 'PCIe' : 'Onboard';
|
275
|
+
currentController.vram = null;
|
276
|
+
currentController.vramDynamic = false;
|
277
|
+
} else if (parts[1].toLowerCase().indexOf(' ltd.') >= 0) {
|
278
|
+
if ((parts[1].match(/]/g) || []).length > 1) {
|
279
|
+
currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(']') + 1).trim();
|
280
|
+
currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf(']') + 1, 200).trim().split('(')[0].trim();
|
281
|
+
} else {
|
282
|
+
currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(' ltd.') + 5).trim();
|
283
|
+
currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf(' ltd.') + 5, 200).trim().split('(')[0].trim();
|
284
|
+
}
|
285
|
+
}
|
286
|
+
}
|
287
|
+
|
288
|
+
} else {
|
289
|
+
isGraphicsController = false;
|
290
|
+
}
|
291
|
+
}
|
292
|
+
if (isGraphicsController) { // within VGA details
|
293
|
+
let parts = line.split(':');
|
294
|
+
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('devicename') !== -1 && parts[1].toLowerCase().indexOf('onboard') !== -1) { currentController.bus = 'Onboard'; }
|
295
|
+
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('region') !== -1 && parts[1].toLowerCase().indexOf('memory') !== -1) {
|
296
|
+
let memparts = parts[1].split('=');
|
297
|
+
if (memparts.length > 1) {
|
298
|
+
currentController.vram = parseInt(memparts[1]);
|
299
|
+
}
|
300
|
+
}
|
301
|
+
}
|
302
|
+
}
|
303
|
+
});
|
304
|
+
|
305
|
+
if (currentController.vendor || currentController.model || currentController.bus || currentController.busAddress || currentController.vram !== null || currentController.vramDynamic) { // already a controller found
|
306
|
+
controllers.push(currentController);
|
307
|
+
}
|
308
|
+
return (controllers);
|
309
|
+
}
|
310
|
+
|
311
|
+
function parseLinesLinuxClinfo(controllers, lines) {
|
312
|
+
const fieldPattern = /\[([^\]]+)\]\s+(\w+)\s+(.*)/;
|
313
|
+
const devices = lines.reduce((devices, line) => {
|
314
|
+
const field = fieldPattern.exec(line.trim());
|
315
|
+
if (field) {
|
316
|
+
if (!devices[field[1]]) {
|
317
|
+
devices[field[1]] = {};
|
318
|
+
}
|
319
|
+
devices[field[1]][field[2]] = field[3];
|
320
|
+
}
|
321
|
+
return devices;
|
322
|
+
}, {});
|
323
|
+
for (let deviceId in devices) {
|
324
|
+
const device = devices[deviceId];
|
325
|
+
if (device['CL_DEVICE_TYPE'] === 'CL_DEVICE_TYPE_GPU') {
|
326
|
+
let busAddress;
|
327
|
+
if (device['CL_DEVICE_TOPOLOGY_AMD']) {
|
328
|
+
const bdf = device['CL_DEVICE_TOPOLOGY_AMD'].match(/[a-zA-Z0-9]+:\d+\.\d+/);
|
329
|
+
if (bdf) {
|
330
|
+
busAddress = bdf[0];
|
331
|
+
}
|
332
|
+
} else if (device['CL_DEVICE_PCI_BUS_ID_NV'] && device['CL_DEVICE_PCI_SLOT_ID_NV']) {
|
333
|
+
const bus = parseInt(device['CL_DEVICE_PCI_BUS_ID_NV']);
|
334
|
+
const slot = parseInt(device['CL_DEVICE_PCI_SLOT_ID_NV']);
|
335
|
+
if (!isNaN(bus) && !isNaN(slot)) {
|
336
|
+
const b = bus & 0xff;
|
337
|
+
const d = (slot >> 3) & 0xff;
|
338
|
+
const f = slot & 0x07;
|
339
|
+
busAddress = `${b.toString().padStart(2, '0')}:${d.toString().padStart(2, '0')}.${f}`;
|
340
|
+
}
|
341
|
+
}
|
342
|
+
if (busAddress) {
|
343
|
+
let controller = controllers.find(controller => controller.busAddress === busAddress);
|
344
|
+
if (!controller) {
|
345
|
+
controller = {
|
346
|
+
vendor: '',
|
347
|
+
model: '',
|
348
|
+
bus: '',
|
349
|
+
busAddress,
|
350
|
+
vram: null,
|
351
|
+
vramDynamic: false
|
352
|
+
};
|
353
|
+
controllers.push(controller);
|
354
|
+
}
|
355
|
+
controller.vendor = device['CL_DEVICE_VENDOR'];
|
356
|
+
if (device['CL_DEVICE_BOARD_NAME_AMD']) {
|
357
|
+
controller.model = device['CL_DEVICE_BOARD_NAME_AMD'];
|
358
|
+
} else {
|
359
|
+
controller.model = device['CL_DEVICE_NAME'];
|
360
|
+
}
|
361
|
+
const memory = parseInt(device['CL_DEVICE_GLOBAL_MEM_SIZE']);
|
362
|
+
if (!isNaN(memory)) {
|
363
|
+
controller.vram = Math.round(memory / 1024 / 1024);
|
364
|
+
}
|
365
|
+
}
|
366
|
+
}
|
367
|
+
}
|
368
|
+
return controllers;
|
369
|
+
}
|
370
|
+
|
371
|
+
function getNvidiaSmi() {
|
372
|
+
if (_nvidiaSmiPath) {
|
373
|
+
return _nvidiaSmiPath;
|
374
|
+
}
|
375
|
+
|
376
|
+
if (_windows) {
|
377
|
+
try {
|
378
|
+
const basePath = util.WINDIR + '\\System32\\DriverStore\\FileRepository';
|
379
|
+
// find all directories that have an nvidia-smi.exe file
|
380
|
+
const candidateDirs = fs.readdirSync(basePath).filter(dir => {
|
381
|
+
return fs.readdirSync([basePath, dir].join('/')).includes('nvidia-smi.exe');
|
382
|
+
});
|
383
|
+
// use the directory with the most recently created nvidia-smi.exe file
|
384
|
+
const targetDir = candidateDirs.reduce((prevDir, currentDir) => {
|
385
|
+
const previousNvidiaSmi = fs.statSync([basePath, prevDir, 'nvidia-smi.exe'].join('/'));
|
386
|
+
const currentNvidiaSmi = fs.statSync([basePath, currentDir, 'nvidia-smi.exe'].join('/'));
|
387
|
+
return (previousNvidiaSmi.ctimeMs > currentNvidiaSmi.ctimeMs) ? prevDir : currentDir;
|
388
|
+
});
|
389
|
+
|
390
|
+
if (targetDir) {
|
391
|
+
_nvidiaSmiPath = [basePath, targetDir, 'nvidia-smi.exe'].join('/');
|
392
|
+
}
|
393
|
+
} catch (e) {
|
394
|
+
util.noop();
|
395
|
+
}
|
396
|
+
} else if (_linux) {
|
397
|
+
_nvidiaSmiPath = 'nvidia-smi';
|
398
|
+
}
|
399
|
+
return _nvidiaSmiPath;
|
400
|
+
}
|
401
|
+
|
402
|
+
function nvidiaSmi(options) {
|
403
|
+
const nvidiaSmiExe = getNvidiaSmi();
|
404
|
+
options = options || util.execOptsWin;
|
405
|
+
if (nvidiaSmiExe) {
|
406
|
+
const nvidiaSmiOpts = '--query-gpu=driver_version,pci.sub_device_id,name,pci.bus_id,fan.speed,memory.total,memory.used,memory.free,utilization.gpu,utilization.memory,temperature.gpu,temperature.memory,power.draw,power.limit,clocks.gr,clocks.mem --format=csv,noheader,nounits';
|
407
|
+
const cmd = nvidiaSmiExe + ' ' + nvidiaSmiOpts + (_linux ? ' 2>/dev/null' : '');
|
408
|
+
try {
|
409
|
+
const res = execSync(cmd, options).toString();
|
410
|
+
return res;
|
411
|
+
} catch (e) {
|
412
|
+
util.noop();
|
413
|
+
}
|
414
|
+
}
|
415
|
+
return '';
|
416
|
+
}
|
417
|
+
|
418
|
+
function nvidiaDevices() {
|
419
|
+
|
420
|
+
function safeParseNumber(value) {
|
421
|
+
if ([null, undefined].includes(value)) {
|
422
|
+
return value;
|
423
|
+
}
|
424
|
+
return parseFloat(value);
|
425
|
+
}
|
426
|
+
|
427
|
+
const stdout = nvidiaSmi();
|
428
|
+
if (!stdout) {
|
429
|
+
return [];
|
430
|
+
}
|
431
|
+
|
432
|
+
const gpus = stdout.split('\n').filter(Boolean);
|
433
|
+
let results = gpus.map(gpu => {
|
434
|
+
const splittedData = gpu.split(', ').map(value => value.includes('N/A') ? undefined : value);
|
435
|
+
if (splittedData.length === 16) {
|
436
|
+
return {
|
437
|
+
driverVersion: splittedData[0],
|
438
|
+
subDeviceId: splittedData[1],
|
439
|
+
name: splittedData[2],
|
440
|
+
pciBus: splittedData[3],
|
441
|
+
fanSpeed: safeParseNumber(splittedData[4]),
|
442
|
+
memoryTotal: safeParseNumber(splittedData[5]),
|
443
|
+
memoryUsed: safeParseNumber(splittedData[6]),
|
444
|
+
memoryFree: safeParseNumber(splittedData[7]),
|
445
|
+
utilizationGpu: safeParseNumber(splittedData[8]),
|
446
|
+
utilizationMemory: safeParseNumber(splittedData[9]),
|
447
|
+
temperatureGpu: safeParseNumber(splittedData[10]),
|
448
|
+
temperatureMemory: safeParseNumber(splittedData[11]),
|
449
|
+
powerDraw: safeParseNumber(splittedData[12]),
|
450
|
+
powerLimit: safeParseNumber(splittedData[13]),
|
451
|
+
clockCore: safeParseNumber(splittedData[14]),
|
452
|
+
clockMemory: safeParseNumber(splittedData[15]),
|
453
|
+
};
|
454
|
+
} else {
|
455
|
+
return {};
|
456
|
+
}
|
457
|
+
});
|
458
|
+
results = results.filter((item) => {
|
459
|
+
return ('pciBus' in item);
|
460
|
+
});
|
461
|
+
return results;
|
462
|
+
}
|
463
|
+
|
464
|
+
function mergeControllerNvidia(controller, nvidia) {
|
465
|
+
if (nvidia.driverVersion) { controller.driverVersion = nvidia.driverVersion; }
|
466
|
+
if (nvidia.subDeviceId) { controller.subDeviceId = nvidia.subDeviceId; }
|
467
|
+
if (nvidia.name) { controller.name = nvidia.name; }
|
468
|
+
if (nvidia.pciBus) { controller.pciBus = nvidia.pciBus; }
|
469
|
+
if (nvidia.fanSpeed) { controller.fanSpeed = nvidia.fanSpeed; }
|
470
|
+
if (nvidia.memoryTotal) {
|
471
|
+
controller.memoryTotal = nvidia.memoryTotal;
|
472
|
+
controller.vram = nvidia.memoryTotal;
|
473
|
+
controller.vramDynamic = false;
|
474
|
+
}
|
475
|
+
if (nvidia.memoryUsed) { controller.memoryUsed = nvidia.memoryUsed; }
|
476
|
+
if (nvidia.memoryFree) { controller.memoryFree = nvidia.memoryFree; }
|
477
|
+
if (nvidia.utilizationGpu) { controller.utilizationGpu = nvidia.utilizationGpu; }
|
478
|
+
if (nvidia.utilizationMemory) { controller.utilizationMemory = nvidia.utilizationMemory; }
|
479
|
+
if (nvidia.temperatureGpu) { controller.temperatureGpu = nvidia.temperatureGpu; }
|
480
|
+
if (nvidia.temperatureMemory) { controller.temperatureMemory = nvidia.temperatureMemory; }
|
481
|
+
if (nvidia.powerDraw) { controller.powerDraw = nvidia.powerDraw; }
|
482
|
+
if (nvidia.powerLimit) { controller.powerLimit = nvidia.powerLimit; }
|
483
|
+
if (nvidia.clockCore) { controller.clockCore = nvidia.clockCore; }
|
484
|
+
if (nvidia.clockMemory) { controller.clockMemory = nvidia.clockMemory; }
|
485
|
+
return controller;
|
486
|
+
}
|
487
|
+
|
488
|
+
function parseLinesLinuxEdid(edid) {
|
489
|
+
// parsen EDID
|
490
|
+
// --> model
|
491
|
+
// --> resolutionx
|
492
|
+
// --> resolutiony
|
493
|
+
// --> builtin = false
|
494
|
+
// --> pixeldepth (?)
|
495
|
+
// --> sizex
|
496
|
+
// --> sizey
|
497
|
+
let result = {
|
498
|
+
vendor: '',
|
499
|
+
model: '',
|
500
|
+
deviceName: '',
|
501
|
+
main: false,
|
502
|
+
builtin: false,
|
503
|
+
connection: '',
|
504
|
+
sizeX: null,
|
505
|
+
sizeY: null,
|
506
|
+
pixelDepth: null,
|
507
|
+
resolutionX: null,
|
508
|
+
resolutionY: null,
|
509
|
+
currentResX: null,
|
510
|
+
currentResY: null,
|
511
|
+
positionX: 0,
|
512
|
+
positionY: 0,
|
513
|
+
currentRefreshRate: null
|
514
|
+
};
|
515
|
+
// find first "Detailed Timing Description"
|
516
|
+
let start = 108;
|
517
|
+
if (edid.substr(start, 6) === '000000') {
|
518
|
+
start += 36;
|
519
|
+
}
|
520
|
+
if (edid.substr(start, 6) === '000000') {
|
521
|
+
start += 36;
|
522
|
+
}
|
523
|
+
if (edid.substr(start, 6) === '000000') {
|
524
|
+
start += 36;
|
525
|
+
}
|
526
|
+
if (edid.substr(start, 6) === '000000') {
|
527
|
+
start += 36;
|
528
|
+
}
|
529
|
+
result.resolutionX = parseInt('0x0' + edid.substr(start + 8, 1) + edid.substr(start + 4, 2));
|
530
|
+
result.resolutionY = parseInt('0x0' + edid.substr(start + 14, 1) + edid.substr(start + 10, 2));
|
531
|
+
result.sizeX = parseInt('0x0' + edid.substr(start + 28, 1) + edid.substr(start + 24, 2));
|
532
|
+
result.sizeY = parseInt('0x0' + edid.substr(start + 29, 1) + edid.substr(start + 26, 2));
|
533
|
+
// monitor name
|
534
|
+
start = edid.indexOf('000000fc00'); // find first "Monitor Description Data"
|
535
|
+
if (start >= 0) {
|
536
|
+
let model_raw = edid.substr(start + 10, 26);
|
537
|
+
if (model_raw.indexOf('0a') !== -1) {
|
538
|
+
model_raw = model_raw.substr(0, model_raw.indexOf('0a'));
|
539
|
+
}
|
540
|
+
try {
|
541
|
+
if (model_raw.length > 2) {
|
542
|
+
result.model = model_raw.match(/.{1,2}/g).map(function (v) {
|
543
|
+
return String.fromCharCode(parseInt(v, 16));
|
544
|
+
}).join('');
|
545
|
+
}
|
546
|
+
} catch (e) {
|
547
|
+
util.noop();
|
548
|
+
}
|
549
|
+
} else {
|
550
|
+
result.model = '';
|
551
|
+
}
|
552
|
+
return result;
|
553
|
+
}
|
554
|
+
|
555
|
+
function parseLinesLinuxDisplays(lines, depth) {
|
556
|
+
let displays = [];
|
557
|
+
let currentDisplay = {
|
558
|
+
vendor: '',
|
559
|
+
model: '',
|
560
|
+
deviceName: '',
|
561
|
+
main: false,
|
562
|
+
builtin: false,
|
563
|
+
connection: '',
|
564
|
+
sizeX: null,
|
565
|
+
sizeY: null,
|
566
|
+
pixelDepth: null,
|
567
|
+
resolutionX: null,
|
568
|
+
resolutionY: null,
|
569
|
+
currentResX: null,
|
570
|
+
currentResY: null,
|
571
|
+
positionX: 0,
|
572
|
+
positionY: 0,
|
573
|
+
currentRefreshRate: null
|
574
|
+
};
|
575
|
+
let is_edid = false;
|
576
|
+
let is_current = false;
|
577
|
+
let edid_raw = '';
|
578
|
+
let start = 0;
|
579
|
+
for (let i = 1; i < lines.length; i++) { // start with second line
|
580
|
+
if ('' !== lines[i].trim()) {
|
581
|
+
if (' ' !== lines[i][0] && '\t' !== lines[i][0] && lines[i].toLowerCase().indexOf(' connected ') !== -1) { // first line of new entry
|
582
|
+
if (currentDisplay.model || currentDisplay.main || currentDisplay.builtin || currentDisplay.connection || currentDisplay.sizeX !== null || currentDisplay.pixelDepth !== null || currentDisplay.resolutionX !== null) { // push last display to array
|
583
|
+
displays.push(currentDisplay);
|
584
|
+
currentDisplay = {
|
585
|
+
vendor: '',
|
586
|
+
model: '',
|
587
|
+
main: false,
|
588
|
+
builtin: false,
|
589
|
+
connection: '',
|
590
|
+
sizeX: null,
|
591
|
+
sizeY: null,
|
592
|
+
pixelDepth: null,
|
593
|
+
resolutionX: null,
|
594
|
+
resolutionY: null,
|
595
|
+
currentResX: null,
|
596
|
+
currentResY: null,
|
597
|
+
positionX: 0,
|
598
|
+
positionY: 0,
|
599
|
+
currentRefreshRate: null
|
600
|
+
};
|
601
|
+
}
|
602
|
+
let parts = lines[i].split(' ');
|
603
|
+
currentDisplay.connection = parts[0];
|
604
|
+
currentDisplay.main = lines[i].toLowerCase().indexOf(' primary ') >= 0;
|
605
|
+
currentDisplay.builtin = (parts[0].toLowerCase().indexOf('edp') >= 0);
|
606
|
+
}
|
607
|
+
|
608
|
+
// try to read EDID information
|
609
|
+
if (is_edid) {
|
610
|
+
if (lines[i].search(/\S|$/) > start) {
|
611
|
+
edid_raw += lines[i].toLowerCase().trim();
|
612
|
+
} else {
|
613
|
+
// parsen EDID
|
614
|
+
let edid_decoded = parseLinesLinuxEdid(edid_raw);
|
615
|
+
currentDisplay.vendor = edid_decoded.vendor;
|
616
|
+
currentDisplay.model = edid_decoded.model;
|
617
|
+
currentDisplay.resolutionX = edid_decoded.resolutionX;
|
618
|
+
currentDisplay.resolutionY = edid_decoded.resolutionY;
|
619
|
+
currentDisplay.sizeX = edid_decoded.sizeX;
|
620
|
+
currentDisplay.sizeY = edid_decoded.sizeY;
|
621
|
+
currentDisplay.pixelDepth = depth;
|
622
|
+
is_edid = false;
|
623
|
+
}
|
624
|
+
}
|
625
|
+
if (lines[i].toLowerCase().indexOf('edid:') >= 0) {
|
626
|
+
is_edid = true;
|
627
|
+
start = lines[i].search(/\S|$/);
|
628
|
+
}
|
629
|
+
if (lines[i].toLowerCase().indexOf('*current') >= 0) {
|
630
|
+
const parts1 = lines[i].split('(');
|
631
|
+
if (parts1 && parts1.length > 1 && parts1[0].indexOf('x') >= 0) {
|
632
|
+
const resParts = parts1[0].trim().split('x');
|
633
|
+
currentDisplay.currentResX = util.toInt(resParts[0]);
|
634
|
+
currentDisplay.currentResY = util.toInt(resParts[1]);
|
635
|
+
}
|
636
|
+
is_current = true;
|
637
|
+
}
|
638
|
+
if (is_current && lines[i].toLowerCase().indexOf('clock') >= 0 && lines[i].toLowerCase().indexOf('hz') >= 0 && lines[i].toLowerCase().indexOf('v: height') >= 0) {
|
639
|
+
const parts1 = lines[i].split('clock');
|
640
|
+
if (parts1 && parts1.length > 1 && parts1[1].toLowerCase().indexOf('hz') >= 0) {
|
641
|
+
currentDisplay.currentRefreshRate = util.toInt(parts1[1]);
|
642
|
+
}
|
643
|
+
is_current = false;
|
644
|
+
}
|
645
|
+
}
|
646
|
+
}
|
647
|
+
|
648
|
+
// pushen displays
|
649
|
+
if (currentDisplay.model || currentDisplay.main || currentDisplay.builtin || currentDisplay.connection || currentDisplay.sizeX !== null || currentDisplay.pixelDepth !== null || currentDisplay.resolutionX !== null) { // still information there
|
650
|
+
displays.push(currentDisplay);
|
651
|
+
}
|
652
|
+
return displays;
|
653
|
+
}
|
654
|
+
|
655
|
+
// function starts here
|
656
|
+
return new Promise((resolve) => {
|
657
|
+
process.nextTick(() => {
|
658
|
+
let result = {
|
659
|
+
controllers: [],
|
660
|
+
displays: []
|
661
|
+
};
|
662
|
+
if (_darwin) {
|
663
|
+
let cmd = 'system_profiler -xml -detailLevel full SPDisplaysDataType';
|
664
|
+
exec(cmd, function (error, stdout) {
|
665
|
+
if (!error) {
|
666
|
+
try {
|
667
|
+
const output = stdout.toString();
|
668
|
+
result = parseLinesDarwin(util.plistParser(output)[0]._items);
|
669
|
+
} catch (e) {
|
670
|
+
util.noop();
|
671
|
+
}
|
672
|
+
stdout = execSync('defaults read /Library/Preferences/com.apple.windowserver.plist 2>/dev/null;defaults read /Library/Preferences/com.apple.windowserver.displays.plist 2>/dev/null; echo ""', { maxBuffer: 1024 * 20000 });
|
673
|
+
const output = (stdout || '').toString();
|
674
|
+
const obj = util.plistReader(output);
|
675
|
+
if (obj['DisplayAnyUserSets'] && obj['DisplayAnyUserSets']['Configs'] && obj['DisplayAnyUserSets']['Configs'][0] && obj['DisplayAnyUserSets']['Configs'][0]['DisplayConfig']) {
|
676
|
+
const current = obj['DisplayAnyUserSets']['Configs'][0]['DisplayConfig'];
|
677
|
+
let i = 0;
|
678
|
+
current.forEach((o) => {
|
679
|
+
if (o['CurrentInfo'] && o['CurrentInfo']['OriginX'] !== undefined && result.displays && result.displays[i]) {
|
680
|
+
result.displays[i].positionX = o['CurrentInfo']['OriginX'];
|
681
|
+
}
|
682
|
+
if (o['CurrentInfo'] && o['CurrentInfo']['OriginY'] !== undefined && result.displays && result.displays[i]) {
|
683
|
+
result.displays[i].positionY = o['CurrentInfo']['OriginY'];
|
684
|
+
}
|
685
|
+
i++;
|
686
|
+
});
|
687
|
+
}
|
688
|
+
if (obj['DisplayAnyUserSets'] && obj['DisplayAnyUserSets'].length > 0 && obj['DisplayAnyUserSets'][0].length > 0 && obj['DisplayAnyUserSets'][0][0]['DisplayID']) {
|
689
|
+
const current = obj['DisplayAnyUserSets'][0];
|
690
|
+
let i = 0;
|
691
|
+
current.forEach((o) => {
|
692
|
+
if ('OriginX' in o && result.displays && result.displays[i]) {
|
693
|
+
result.displays[i].positionX = o['OriginX'];
|
694
|
+
}
|
695
|
+
if ('OriginY' in o && result.displays && result.displays[i]) {
|
696
|
+
result.displays[i].positionY = o['OriginY'];
|
697
|
+
}
|
698
|
+
if (o['Mode'] && o['Mode']['BitsPerPixel'] !== undefined && result.displays && result.displays[i]) {
|
699
|
+
result.displays[i].pixelDepth = o['Mode']['BitsPerPixel'];
|
700
|
+
}
|
701
|
+
i++;
|
702
|
+
});
|
703
|
+
}
|
704
|
+
|
705
|
+
}
|
706
|
+
if (callback) {
|
707
|
+
callback(result);
|
708
|
+
}
|
709
|
+
resolve(result);
|
710
|
+
});
|
711
|
+
}
|
712
|
+
if (_linux) {
|
713
|
+
// Raspberry: https://elinux.org/RPI_vcgencmd_usage
|
714
|
+
if (util.isRaspberry() && util.isRaspbian()) {
|
715
|
+
let cmd = 'fbset -s | grep \'mode "\'; vcgencmd get_mem gpu; tvservice -s; tvservice -n;';
|
716
|
+
exec(cmd, function (error, stdout) {
|
717
|
+
let lines = stdout.toString().split('\n');
|
718
|
+
if (lines.length > 3 && lines[0].indexOf('mode "') >= -1 && lines[2].indexOf('0x12000a') > -1) {
|
719
|
+
const parts = lines[0].replace('mode', '').replace(/"/g, '').trim().split('x');
|
720
|
+
if (parts.length === 2) {
|
721
|
+
result.displays.push({
|
722
|
+
vendor: '',
|
723
|
+
model: util.getValue(lines, 'device_name', '='),
|
724
|
+
main: true,
|
725
|
+
builtin: false,
|
726
|
+
connection: 'HDMI',
|
727
|
+
sizeX: null,
|
728
|
+
sizeY: null,
|
729
|
+
pixelDepth: null,
|
730
|
+
resolutionX: parseInt(parts[0], 10),
|
731
|
+
resolutionY: parseInt(parts[1], 10),
|
732
|
+
currentResX: null,
|
733
|
+
currentResY: null,
|
734
|
+
positionX: 0,
|
735
|
+
positionY: 0,
|
736
|
+
currentRefreshRate: null
|
737
|
+
});
|
738
|
+
}
|
739
|
+
}
|
740
|
+
if (lines.length > 1 && stdout.toString().indexOf('gpu=') >= -1) {
|
741
|
+
result.controllers.push({
|
742
|
+
vendor: 'Broadcom',
|
743
|
+
model: 'VideoCore IV',
|
744
|
+
bus: '',
|
745
|
+
vram: util.getValue(lines, 'gpu', '=').replace('M', ''),
|
746
|
+
vramDynamic: true
|
747
|
+
});
|
748
|
+
}
|
749
|
+
if (callback) {
|
750
|
+
callback(result);
|
751
|
+
}
|
752
|
+
resolve(result);
|
753
|
+
});
|
754
|
+
} else {
|
755
|
+
let cmd = 'lspci -vvv 2>/dev/null';
|
756
|
+
exec(cmd, function (error, stdout) {
|
757
|
+
if (!error) {
|
758
|
+
let lines = stdout.toString().split('\n');
|
759
|
+
result.controllers = parseLinesLinuxControllers(lines);
|
760
|
+
const nvidiaData = nvidiaDevices();
|
761
|
+
// needs to be rewritten ... using no spread operators
|
762
|
+
result.controllers = result.controllers.map((controller) => { // match by busAddress
|
763
|
+
return mergeControllerNvidia(controller, nvidiaData.find((contr) => contr.pciBus.toLowerCase().endsWith(controller.busAddress.toLowerCase())) || {});
|
764
|
+
});
|
765
|
+
}
|
766
|
+
let cmd = 'clinfo --raw';
|
767
|
+
exec(cmd, function (error, stdout) {
|
768
|
+
if (!error) {
|
769
|
+
let lines = stdout.toString().split('\n');
|
770
|
+
result.controllers = parseLinesLinuxClinfo(result.controllers, lines);
|
771
|
+
}
|
772
|
+
let cmd = 'xdpyinfo 2>/dev/null | grep \'depth of root window\' | awk \'{ print $5 }\'';
|
773
|
+
exec(cmd, function (error, stdout) {
|
774
|
+
let depth = 0;
|
775
|
+
if (!error) {
|
776
|
+
let lines = stdout.toString().split('\n');
|
777
|
+
depth = parseInt(lines[0]) || 0;
|
778
|
+
}
|
779
|
+
let cmd = 'xrandr --verbose 2>/dev/null';
|
780
|
+
exec(cmd, function (error, stdout) {
|
781
|
+
if (!error) {
|
782
|
+
let lines = stdout.toString().split('\n');
|
783
|
+
result.displays = parseLinesLinuxDisplays(lines, depth);
|
784
|
+
}
|
785
|
+
if (callback) {
|
786
|
+
callback(result);
|
787
|
+
}
|
788
|
+
resolve(result);
|
789
|
+
});
|
790
|
+
});
|
791
|
+
});
|
792
|
+
});
|
793
|
+
}
|
794
|
+
}
|
795
|
+
if (_freebsd || _openbsd || _netbsd) {
|
796
|
+
if (callback) { callback(null); }
|
797
|
+
resolve(null);
|
798
|
+
}
|
799
|
+
if (_sunos) {
|
800
|
+
if (callback) { callback(null); }
|
801
|
+
resolve(null);
|
802
|
+
}
|
803
|
+
if (_windows) {
|
804
|
+
|
805
|
+
// https://blogs.technet.microsoft.com/heyscriptingguy/2013/10/03/use-powershell-to-discover-multi-monitor-information/
|
806
|
+
// https://devblogs.microsoft.com/scripting/use-powershell-to-discover-multi-monitor-information/
|
807
|
+
try {
|
808
|
+
const workload = [];
|
809
|
+
workload.push(util.powerShell('Get-CimInstance win32_VideoController | fl *'));
|
810
|
+
workload.push(util.powerShell('gp "HKLM:\\SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\*" -ErrorAction SilentlyContinue | where MatchingDeviceId $null -NE | select MatchingDeviceId,HardwareInformation.qwMemorySize | fl'));
|
811
|
+
workload.push(util.powerShell('Get-CimInstance win32_desktopmonitor | fl *'));
|
812
|
+
workload.push(util.powerShell('Get-CimInstance -Namespace root\\wmi -ClassName WmiMonitorBasicDisplayParams | fl'));
|
813
|
+
workload.push(util.powerShell('Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Screen]::AllScreens'));
|
814
|
+
workload.push(util.powerShell('Get-CimInstance -Namespace root\\wmi -ClassName WmiMonitorConnectionParams | fl'));
|
815
|
+
workload.push(util.powerShell('gwmi WmiMonitorID -Namespace root\\wmi | ForEach-Object {(($_.ManufacturerName -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.ProductCodeID -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.UserFriendlyName -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.SerialNumberID -notmatch 0 | foreach {[char]$_}) -join "") + "|" + $_.InstanceName}'));
|
816
|
+
|
817
|
+
const nvidiaData = nvidiaDevices();
|
818
|
+
|
819
|
+
Promise.all(
|
820
|
+
workload
|
821
|
+
).then((data) => {
|
822
|
+
// controller + vram
|
823
|
+
let csections = data[0].replace(/\r/g, '').split(/\n\s*\n/);
|
824
|
+
let vsections = data[1].replace(/\r/g, '').split(/\n\s*\n/);
|
825
|
+
result.controllers = parseLinesWindowsControllers(csections, vsections);
|
826
|
+
result.controllers = result.controllers.map((controller) => { // match by subDeviceId
|
827
|
+
if (controller.vendor.toLowerCase() === 'nvidia') {
|
828
|
+
return mergeControllerNvidia(controller, nvidiaData.find(device => {
|
829
|
+
let windowsSubDeviceId = (controller.subDeviceId || '').toLowerCase();
|
830
|
+
const nvidiaSubDeviceIdParts = device.subDeviceId.split('x');
|
831
|
+
let nvidiaSubDeviceId = nvidiaSubDeviceIdParts.length > 1 ? nvidiaSubDeviceIdParts[1].toLowerCase() : nvidiaSubDeviceIdParts[0].toLowerCase();
|
832
|
+
const lengthDifference = Math.abs(windowsSubDeviceId.length - nvidiaSubDeviceId.length);
|
833
|
+
if (windowsSubDeviceId.length > nvidiaSubDeviceId.length) {
|
834
|
+
for (let i = 0; i < lengthDifference; i++) {
|
835
|
+
nvidiaSubDeviceId = '0' + nvidiaSubDeviceId;
|
836
|
+
}
|
837
|
+
} else if (windowsSubDeviceId.length < nvidiaSubDeviceId.length) {
|
838
|
+
for (let i = 0; i < lengthDifference; i++) {
|
839
|
+
windowsSubDeviceId = '0' + windowsSubDeviceId;
|
840
|
+
}
|
841
|
+
}
|
842
|
+
return windowsSubDeviceId === nvidiaSubDeviceId;
|
843
|
+
}) || {});
|
844
|
+
} else {
|
845
|
+
return controller;
|
846
|
+
}
|
847
|
+
});
|
848
|
+
|
849
|
+
// displays
|
850
|
+
let dsections = data[2].replace(/\r/g, '').split(/\n\s*\n/);
|
851
|
+
// result.displays = parseLinesWindowsDisplays(dsections);
|
852
|
+
if (dsections[0].trim() === '') { dsections.shift(); }
|
853
|
+
if (dsections.length && dsections[dsections.length - 1].trim() === '') { dsections.pop(); }
|
854
|
+
|
855
|
+
// monitor (powershell)
|
856
|
+
let msections = data[3].replace(/\r/g, '').split('Active ');
|
857
|
+
msections.shift();
|
858
|
+
|
859
|
+
// forms.screens (powershell)
|
860
|
+
let ssections = data[4].replace(/\r/g, '').split('BitsPerPixel ');
|
861
|
+
ssections.shift();
|
862
|
+
|
863
|
+
// connection params (powershell) - video type
|
864
|
+
let tsections = data[5].replace(/\r/g, '').split(/\n\s*\n/);
|
865
|
+
tsections.shift();
|
866
|
+
|
867
|
+
// monitor ID (powershell) - model / vendor
|
868
|
+
const res = data[6].replace(/\r/g, '').split(/\n/);
|
869
|
+
let isections = [];
|
870
|
+
res.forEach(element => {
|
871
|
+
const parts = element.split('|');
|
872
|
+
if (parts.length === 5) {
|
873
|
+
isections.push({
|
874
|
+
vendor: parts[0],
|
875
|
+
code: parts[1],
|
876
|
+
model: parts[2],
|
877
|
+
serial: parts[3],
|
878
|
+
instanceId: parts[4]
|
879
|
+
});
|
880
|
+
}
|
881
|
+
});
|
882
|
+
|
883
|
+
result.displays = parseLinesWindowsDisplaysPowershell(ssections, msections, dsections, tsections, isections);
|
884
|
+
|
885
|
+
if (result.displays.length === 1) {
|
886
|
+
if (_resolutionX) {
|
887
|
+
result.displays[0].resolutionX = _resolutionX;
|
888
|
+
if (!result.displays[0].currentResX) {
|
889
|
+
result.displays[0].currentResX = _resolutionX;
|
890
|
+
}
|
891
|
+
}
|
892
|
+
if (_resolutionY) {
|
893
|
+
result.displays[0].resolutionY = _resolutionY;
|
894
|
+
if (result.displays[0].currentResY === 0) {
|
895
|
+
result.displays[0].currentResY = _resolutionY;
|
896
|
+
}
|
897
|
+
}
|
898
|
+
if (_pixelDepth) {
|
899
|
+
result.displays[0].pixelDepth = _pixelDepth;
|
900
|
+
}
|
901
|
+
}
|
902
|
+
result.displays = result.displays.map(element => {
|
903
|
+
if (_refreshRate && !element.currentRefreshRate) {
|
904
|
+
element.currentRefreshRate = _refreshRate;
|
905
|
+
}
|
906
|
+
return element;
|
907
|
+
});
|
908
|
+
|
909
|
+
if (callback) {
|
910
|
+
callback(result);
|
911
|
+
}
|
912
|
+
resolve(result);
|
913
|
+
})
|
914
|
+
.catch(() => {
|
915
|
+
if (callback) {
|
916
|
+
callback(result);
|
917
|
+
}
|
918
|
+
resolve(result);
|
919
|
+
});
|
920
|
+
} catch (e) {
|
921
|
+
if (callback) { callback(result); }
|
922
|
+
resolve(result);
|
923
|
+
}
|
924
|
+
}
|
925
|
+
});
|
926
|
+
});
|
927
|
+
|
928
|
+
function parseLinesWindowsControllers(sections, vections) {
|
929
|
+
const memorySizes = {};
|
930
|
+
for (const i in vections) {
|
931
|
+
if ({}.hasOwnProperty.call(vections, i)) {
|
932
|
+
if (vections[i].trim() !== '') {
|
933
|
+
const lines = vections[i].trim().split('\n');
|
934
|
+
const matchingDeviceId = util.getValue(lines, 'MatchingDeviceId').match(/PCI\\(VEN_[0-9A-F]{4})&(DEV_[0-9A-F]{4})(?:&(SUBSYS_[0-9A-F]{8}))?(?:&(REV_[0-9A-F]{2}))?/i);
|
935
|
+
if (matchingDeviceId) {
|
936
|
+
const quadWordmemorySize = parseInt(util.getValue(lines, 'HardwareInformation.qwMemorySize'));
|
937
|
+
if (!isNaN(quadWordmemorySize)) {
|
938
|
+
let deviceId = matchingDeviceId[1].toUpperCase() + '&' + matchingDeviceId[2].toUpperCase();
|
939
|
+
if (matchingDeviceId[3]) {
|
940
|
+
deviceId += '&' + matchingDeviceId[3].toUpperCase();
|
941
|
+
}
|
942
|
+
if (matchingDeviceId[4]) {
|
943
|
+
deviceId += '&' + matchingDeviceId[4].toUpperCase();
|
944
|
+
}
|
945
|
+
memorySizes[deviceId] = quadWordmemorySize;
|
946
|
+
}
|
947
|
+
}
|
948
|
+
}
|
949
|
+
}
|
950
|
+
}
|
951
|
+
|
952
|
+
let controllers = [];
|
953
|
+
for (let i in sections) {
|
954
|
+
if ({}.hasOwnProperty.call(sections, i)) {
|
955
|
+
if (sections[i].trim() !== '') {
|
956
|
+
let lines = sections[i].trim().split('\n');
|
957
|
+
let pnpDeviceId = util.getValue(lines, 'PNPDeviceID', ':').match(/PCI\\(VEN_[0-9A-F]{4})&(DEV_[0-9A-F]{4})(?:&(SUBSYS_[0-9A-F]{8}))?(?:&(REV_[0-9A-F]{2}))?/i);
|
958
|
+
let subDeviceId = null;
|
959
|
+
let memorySize = null;
|
960
|
+
if (pnpDeviceId) {
|
961
|
+
subDeviceId = pnpDeviceId[3] || '';
|
962
|
+
if (subDeviceId) {
|
963
|
+
subDeviceId = subDeviceId.split('_')[1];
|
964
|
+
}
|
965
|
+
|
966
|
+
// Match PCI device identifier (there's an order of increasing generality):
|
967
|
+
// https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-pci-devices
|
968
|
+
|
969
|
+
// PCI\VEN_v(4)&DEV_d(4)&SUBSYS_s(4)n(4)&REV_r(2)
|
970
|
+
if (memorySize == null && pnpDeviceId[3] && pnpDeviceId[4]) {
|
971
|
+
const deviceId = pnpDeviceId[1].toUpperCase() + '&' + pnpDeviceId[2].toUpperCase() + '&' + pnpDeviceId[3].toUpperCase() + '&' + pnpDeviceId[4].toUpperCase();
|
972
|
+
if ({}.hasOwnProperty.call(memorySizes, deviceId)) {
|
973
|
+
memorySize = memorySizes[deviceId];
|
974
|
+
}
|
975
|
+
}
|
976
|
+
|
977
|
+
// PCI\VEN_v(4)&DEV_d(4)&SUBSYS_s(4)n(4)
|
978
|
+
if (memorySize == null && pnpDeviceId[3]) {
|
979
|
+
const deviceId = pnpDeviceId[1].toUpperCase() + '&' + pnpDeviceId[2].toUpperCase() + '&' + pnpDeviceId[3].toUpperCase();
|
980
|
+
if ({}.hasOwnProperty.call(memorySizes, deviceId)) {
|
981
|
+
memorySize = memorySizes[deviceId];
|
982
|
+
}
|
983
|
+
}
|
984
|
+
|
985
|
+
// PCI\VEN_v(4)&DEV_d(4)&REV_r(2)
|
986
|
+
if (memorySize == null && pnpDeviceId[4]) {
|
987
|
+
const deviceId = pnpDeviceId[1].toUpperCase() + '&' + pnpDeviceId[2].toUpperCase() + '&' + pnpDeviceId[4].toUpperCase();
|
988
|
+
if ({}.hasOwnProperty.call(memorySizes, deviceId)) {
|
989
|
+
memorySize = memorySizes[deviceId];
|
990
|
+
}
|
991
|
+
}
|
992
|
+
|
993
|
+
// PCI\VEN_v(4)&DEV_d(4)
|
994
|
+
if (memorySize == null) {
|
995
|
+
const deviceId = pnpDeviceId[1].toUpperCase() + '&' + pnpDeviceId[2].toUpperCase();
|
996
|
+
if ({}.hasOwnProperty.call(memorySizes, deviceId)) {
|
997
|
+
memorySize = memorySizes[deviceId];
|
998
|
+
}
|
999
|
+
}
|
1000
|
+
}
|
1001
|
+
|
1002
|
+
controllers.push({
|
1003
|
+
vendor: util.getValue(lines, 'AdapterCompatibility', ':'),
|
1004
|
+
model: util.getValue(lines, 'name', ':'),
|
1005
|
+
bus: util.getValue(lines, 'PNPDeviceID', ':').startsWith('PCI') ? 'PCI' : '',
|
1006
|
+
vram: (memorySize == null ? util.toInt(util.getValue(lines, 'AdapterRAM', ':')) : memorySize) / 1024 / 1024,
|
1007
|
+
vramDynamic: (util.getValue(lines, 'VideoMemoryType', ':') === '2'),
|
1008
|
+
subDeviceId
|
1009
|
+
});
|
1010
|
+
_resolutionX = util.toInt(util.getValue(lines, 'CurrentHorizontalResolution', ':')) || _resolutionX;
|
1011
|
+
_resolutionY = util.toInt(util.getValue(lines, 'CurrentVerticalResolution', ':')) || _resolutionY;
|
1012
|
+
_refreshRate = util.toInt(util.getValue(lines, 'CurrentRefreshRate', ':')) || _refreshRate;
|
1013
|
+
_pixelDepth = util.toInt(util.getValue(lines, 'CurrentBitsPerPixel', ':')) || _pixelDepth;
|
1014
|
+
}
|
1015
|
+
}
|
1016
|
+
}
|
1017
|
+
return controllers;
|
1018
|
+
}
|
1019
|
+
|
1020
|
+
function parseLinesWindowsDisplaysPowershell(ssections, msections, dsections, tsections, isections) {
|
1021
|
+
let displays = [];
|
1022
|
+
let vendor = '';
|
1023
|
+
let model = '';
|
1024
|
+
let deviceID = '';
|
1025
|
+
let resolutionX = 0;
|
1026
|
+
let resolutionY = 0;
|
1027
|
+
if (dsections && dsections.length) {
|
1028
|
+
let linesDisplay = dsections[0].split('\n');
|
1029
|
+
vendor = util.getValue(linesDisplay, 'MonitorManufacturer', ':');
|
1030
|
+
model = util.getValue(linesDisplay, 'Name', ':');
|
1031
|
+
deviceID = util.getValue(linesDisplay, 'PNPDeviceID', ':').replace(/&/g, '&').toLowerCase();
|
1032
|
+
resolutionX = util.toInt(util.getValue(linesDisplay, 'ScreenWidth', ':'));
|
1033
|
+
resolutionY = util.toInt(util.getValue(linesDisplay, 'ScreenHeight', ':'));
|
1034
|
+
}
|
1035
|
+
for (let i = 0; i < ssections.length; i++) {
|
1036
|
+
if (ssections[i].trim() !== '') {
|
1037
|
+
ssections[i] = 'BitsPerPixel ' + ssections[i];
|
1038
|
+
msections[i] = 'Active ' + msections[i];
|
1039
|
+
// tsections can be empty OR undefined on earlier versions of powershell (<=2.0)
|
1040
|
+
// Tag connection type as UNKNOWN by default if this information is missing
|
1041
|
+
if (tsections.length === 0 || tsections[i] === undefined) {
|
1042
|
+
tsections[i] = 'Unknown';
|
1043
|
+
}
|
1044
|
+
let linesScreen = ssections[i].split('\n');
|
1045
|
+
let linesMonitor = msections[i].split('\n');
|
1046
|
+
|
1047
|
+
let linesConnection = tsections[i].split('\n');
|
1048
|
+
const bitsPerPixel = util.getValue(linesScreen, 'BitsPerPixel');
|
1049
|
+
const bounds = util.getValue(linesScreen, 'Bounds').replace('{', '').replace('}', '').replace(/=/g, ':').split(',');
|
1050
|
+
const primary = util.getValue(linesScreen, 'Primary');
|
1051
|
+
const sizeX = util.getValue(linesMonitor, 'MaxHorizontalImageSize');
|
1052
|
+
const sizeY = util.getValue(linesMonitor, 'MaxVerticalImageSize');
|
1053
|
+
const instanceName = util.getValue(linesMonitor, 'InstanceName').toLowerCase();
|
1054
|
+
const videoOutputTechnology = util.getValue(linesConnection, 'VideoOutputTechnology');
|
1055
|
+
const deviceName = util.getValue(linesScreen, 'DeviceName');
|
1056
|
+
let displayVendor = '';
|
1057
|
+
let displayModel = '';
|
1058
|
+
isections.forEach(element => {
|
1059
|
+
if (element.instanceId.toLowerCase().startsWith(instanceName) && vendor.startsWith('(') && model.startsWith('PnP')) {
|
1060
|
+
displayVendor = element.vendor;
|
1061
|
+
displayModel = element.model;
|
1062
|
+
}
|
1063
|
+
});
|
1064
|
+
displays.push({
|
1065
|
+
vendor: instanceName.startsWith(deviceID) && displayVendor === '' ? vendor : displayVendor,
|
1066
|
+
model: instanceName.startsWith(deviceID) && displayModel === '' ? model : displayModel,
|
1067
|
+
deviceName,
|
1068
|
+
main: primary.toLowerCase() === 'true',
|
1069
|
+
builtin: videoOutputTechnology === '2147483648',
|
1070
|
+
connection: videoOutputTechnology && videoTypes[videoOutputTechnology] ? videoTypes[videoOutputTechnology] : '',
|
1071
|
+
resolutionX: util.toInt(util.getValue(bounds, 'Width', ':')),
|
1072
|
+
resolutionY: util.toInt(util.getValue(bounds, 'Height', ':')),
|
1073
|
+
sizeX: sizeX ? parseInt(sizeX, 10) : null,
|
1074
|
+
sizeY: sizeY ? parseInt(sizeY, 10) : null,
|
1075
|
+
pixelDepth: bitsPerPixel,
|
1076
|
+
currentResX: util.toInt(util.getValue(bounds, 'Width', ':')),
|
1077
|
+
currentResY: util.toInt(util.getValue(bounds, 'Height', ':')),
|
1078
|
+
positionX: util.toInt(util.getValue(bounds, 'X', ':')),
|
1079
|
+
positionY: util.toInt(util.getValue(bounds, 'Y', ':')),
|
1080
|
+
});
|
1081
|
+
}
|
1082
|
+
}
|
1083
|
+
if (ssections.length === 0) {
|
1084
|
+
displays.push({
|
1085
|
+
vendor,
|
1086
|
+
model,
|
1087
|
+
main: true,
|
1088
|
+
sizeX: null,
|
1089
|
+
sizeY: null,
|
1090
|
+
resolutionX,
|
1091
|
+
resolutionY,
|
1092
|
+
pixelDepth: null,
|
1093
|
+
currentResX: resolutionX,
|
1094
|
+
currentResY: resolutionY,
|
1095
|
+
positionX: 0,
|
1096
|
+
positionY: 0
|
1097
|
+
});
|
1098
|
+
}
|
1099
|
+
return displays;
|
1100
|
+
}
|
1101
|
+
}
|
1102
|
+
|
1103
|
+
exports.graphics = graphics;
|