Commit 02450efe authored by Alexandra Rogova's avatar Alexandra Rogova

added systeminformation package

parent 43bb64f8
...@@ -17,6 +17,7 @@ if (!(args.saveAs === "metadata" ||args.saveAs === "attachment")){ ...@@ -17,6 +17,7 @@ if (!(args.saveAs === "metadata" ||args.saveAs === "attachment")){
var saveAs = args.saveAs; var saveAs = args.saveAs;
var browser; var browser;
var Server = require('ws').Server; var Server = require('ws').Server;
var port = 9030; var port = 9030;
var ws = new Server({port: port}); var ws = new Server({port: port});
...@@ -35,6 +36,10 @@ var ws = new Server({port: port}); ...@@ -35,6 +36,10 @@ var ws = new Server({port: port});
}); });
(async () => { (async () => {
const used = process.memoryUsage();
for (let key in used) {
console.log(`${key} ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`);
}
browser = await puppeteer.launch(); browser = await puppeteer.launch();
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto('https://softinst115787.host.vifib.net/public/unit_tests/index_load.html?saveAs='+saveAs); await page.goto('https://softinst115787.host.vifib.net/public/unit_tests/index_load.html?saveAs='+saveAs);
...@@ -43,8 +48,4 @@ var ws = new Server({port: port}); ...@@ -43,8 +48,4 @@ var ws = new Server({port: port});
page.click('input#load') page.click('input#load')
]); ]);
await fileChooser.accept([args.file]); await fileChooser.accept([args.file]);
const used = process.memoryUsage();
for (let key in used) {
console.log(`${key} ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`);
}
})(); })();
# Changelog
### Major Changes - Version 4
**New Functions**
- `chassis()`: chassis information
**Breaking Changes**
- `networkStats()`: will provide an **array** of stats for all given interfaces. In previous versions only one interface was provided as a parameter. Pass '*' for all interfaces
- `networkStats()`: `rx` and `tx` changed to `rx_bytes` and `tx_bytes`
- `dockerContainerStats()`: will provide an **array** of stats for all given docker containers. In previous versions only one interface was provided as a parameter. Pass '*' for all docker containers
**Other Changes**
- `system()` optimized system detection (e.g. new Raspberry Pi models, ...)
- `system()`, `bios()`, `baseboard()` information also as non-root (linux)
- `graphics()` better controller and display detection, fixes
- `versions()` optimization, fixes
- `networkInterfaces()` added `operstate`, `type`, `duplex`, `mtu`, `speed`, `carrierChanges`
- `networkStats()` added stats for `errors`, `dropped`
- added TypeScript definitions
**Be aware**, that the new version 4.x is **NOT fully backward compatible** to version 3.x ...
For major (breaking) changes - version 3 and 2 see end of page.
## Version history
| Version | Date | Comment |
| -------------- | -------------- | -------- |
| 4.14.11 | 2019-10-01 | type definitions fix dockerInfo |
| 4.14.10 | 2019-10-01 | type definitions fix memLayout |
| 4.14.9 | 2019-10-01 | `processLoad()` fix windows |
| 4.14.8 | 2019-08-22 | `parseDateTime()` fix coding error |
| 4.14.7 | 2019-08-22 | `battery()` windows acconnected improvement |
| 4.14.6 | 2019-08-22 | `users()` improved date time parsing |
| 4.14.5 | 2019-08-22 | `fsSize()` fix windows result as number |
| 4.14.4 | 2019-07-20 | `verions()` fix pip, pip3 |
| 4.14.3 | 2019-07-09 | `system()` sku fix windows |
| 4.14.2 | 2019-07-07 | `networkConnections()` pid linux fix NAN |
| 4.14.1 | 2019-07-04 | `graphics()` added display position windows |
| 4.14.0 | 2019-07-03 | `processes()` added process path and params |
| 4.13.2 | 2019-07-02 | `versions()` fix getting all versions |
| 4.13.1 | 2019-07-01 | `versions()` gcc fix macos |
| 4.13.0 | 2019-07-01 | `networkConnections()` added PID and process |
| 4.12.2 | 2019-06-24 | `system()` added Raspberry PI 4 detection |
| 4.12.1 | 2019-06-24 | `networkInterface()` virtual interfaces macos, `networkInterfaceDefault()` |
| 4.12.0 | 2019-06-21 | `networkInterface()` added property virtual |
| 4.11.6 | 2019-06-19 | `util` bug fix |
| 4.11.5 | 2019-06-19 | `dockerAll()` bug fix |
| 4.11.4 | 2019-06-17 | type definitions bug fix |
| 4.11.3 | 2019-06-16 | `graphics()` optimization windows |
| 4.11.2 | 2019-06-16 | `wifiNetworks()` bug fixes |
| 4.11.1 | 2019-06-15 | updated docs |
| 4.11.0 | 2019-06-14 | `wifiNetworks()` added available wifi networks |
| 4.10.0 | 2019-06-14 | `graphics()` windows multiple display support |
| 4.9.2 | 2019-06-12 | type definitions bug fix |
| 4.9.1 | 2019-06-11 | `networkStats()` bug fix windows |
| 4.9.0 | 2019-06-03 | `graphics()` added vendor, refresh rate, current res |
| 4.8.4 | 2019-06-03 | `vboxInfo()` fixed call parameters |
| 4.8.3 | 2019-06-01 | `vboxInfo()` added stoppedSince, started, stopped |
| 4.8.2 | 2019-05-31 | `dockerInfo()` changed property naming style |
| 4.8.1 | 2019-05-31 | updated docs |
| 4.8.0 | 2019-05-31 | added `vboxInfo()` detailed virtual box info |
| 4.7.3 | 2019-05-30 | updated typescript typings |
| 4.7.2 | 2019-05-30 | `versions()` added virtualbox, java popup fix macos |
| 4.7.1 | 2019-05-29 | `memLayout()` fix macos mojave |
| 4.7.0 | 2019-05-29 | partial netBSD support |
| 4.6.1 | 2019-05-29 | get wmic path - fic windows |
| 4.6.0 | 2019-05-27 | added `dockerInfo()` |
| 4.5.1 | 2019-05-17 | updated docs |
| 4.5.0 | 2019-05-17 | `fsOpenFiles()` added open file descriptor count |
| 4.4.1 | 2019-05-11 | updated docs |
| 4.4.0 | 2019-05-11 | `dockerContainers()` added started, finished time |
| 4.3.0 | 2019-05-09 | `dockerContainers()` `dockerStats()` added restartCount |
| 4.2.1 | 2019-05-09 | `networkInterfaceDefault()` time delay fix (linux) |
| 4.2.0 | 2019-05-09 | `osInfo()` extended service pack version (windows) |
| 4.1.8 | 2019-05-09 | `graphics()` resolve on error (windows) |
| 4.1.7 | 2019-05-09 | `users()` parsing fix (windows) |
| 4.1.6 | 2019-04-24 | `memory()` swap used fix (linux) |
| 4.1.5 | 2019-04-19 | refactored `wmic` calls to work also on Windows XP |
| 4.1.4 | 2019-03-26 | `networkInterfaces()` speed bug (windows) |
| 4.1.3 | 2019-03-24 | wmic path detection (windows) |
| 4.1.2 | 2019-03-23 | updated docs |
| 4.1.1 | 2019-03-13 | updated typescript typings |
| 4.1.0 | 2019-03-13 | `versions()` added pip, pip3 |
| 4.0.16 | 2019-03-12 | Happy birthday - 5th aniversary |
| 4.0.15 | 2019-03-02 | `versions()` added java, python3, optimized gcc |
| 4.0.14 | 2019-03-01 | updated typescript typings |
| 4.0.13 | 2019-03-01 | `diskLayout()` added device (/dev/sda...) linux, mac |
| 4.0.12 | 2019-03-01 | `diskLayout()` linux rewritten - better detection |
| 4.0.11 | 2019-02-23 | `users()` fix windows (time), added @ts-check |
| 4.0.10 | 2019-02-10 | `networkInterfaceDefault()` fix windows |
| 4.0.9 | 2019-02-08 | `cpu()` fix, code cleanup |
| 4.0.8 | 2019-02-05 | `inetLatency()` Windows fix parse chinese output |
| 4.0.7 | 2019-02-05 | `inetLatency()` Windows fix |
| 4.0.6 | 2019-02-04 | powershell catch error |
| 4.0.5 | 2019-02-03 | updated docs |
| 4.0.4 | 2019-02-03 | code cleanup, updated docs |
| 4.0.3 | 2019-02-03 | `networkInterfaces(), chassis()` fixed two more issues |
| 4.0.2 | 2019-02-03 | `networkInterfaces(), chassis()` fixed smaller issues |
| 4.0.1 | 2019-02-02 | updated docs |
| 4.0.0 | 2019-02-02 | new major version |
| 3.54.0 | 2018-12-30 | added TypeScript type definitions |
| 3.53.1 | 2018-12-29 | `versions()` bug fix nginx version |
| 3.53.0 | 2018-12-29 | `versions()` added perl, python, gcc |
| 3.52.7 | 2018-12-29 | `versions()` bug fix macOS detection |
| 3.52.6 | 2018-12-28 | `versions()` bug fix macOS |
| 3.52.5 | 2018-12-28 | preparing automated tests, travis-ci integration, added dev-dependencies |
| 3.52.4 | 2018-12-27 | `graphics().controllers` bugfix linux |
| 3.52.3 | 2018-12-27 | `os().codepage` bugfix |
| 3.52.2 | 2018-12-17 | code cleanup |
| 3.52.1 | 2018-12-17 | `inetChecksite()` bugfix windows |
| 3.52.0 | 2018-12-15 | `cpu()` added physical cores, processors, socket type |
| 3.51.4 | 2018-12-05 | `versions()` bugfix, optimization postgres |
| 3.51.3 | 2018-11-27 | `mem()` refactoring parsing linux, code cleanup |
| 3.51.2 | 2018-11-26 | `mem()` bugfix parsing `free` output linux |
| 3.51.1 | 2018-11-26 | `processLoad()` bugfix windows |
| 3.51.0 | 2018-11-25 | `processLoad()` added for windows |
| 3.50.3 | 2018-11-25 | `processLoad()`, `services()` fixed cpu data (linux) |
| 3.50.2 | 2018-11-23 | network mac adresses: ip support fix |
| 3.50.1 | 2018-11-23 | `services()` added possibility to specify ALL services "*" for win |
| 3.50.0 | 2018-11-23 | `services()` added possibility to specify ALL services "*" for linux |
| 3.49.4 | 2018-11-21 | `battery()` timeremaining optimization (linux) thanks to Jorai Rijsdijk |
| 3.49.3 | 2018-11-20 | `memLayout()` optimized parsing (win) |
| 3.49.2 | 2018-11-19 | code cleanup |
| 3.49.1 | 2018-11-19 | `cpu().brand` removed extra spaces, tabs |
| 3.49.0 | 2018-11-19 | added system `uuid()` (os specific), `versions()` added postgresql |
| 3.48.4 | 2018-11-18 | windows: garbled output because of codepage |
| 3.48.3 | 2018-11-18 | `dockerContainerStats()` fixed issue `cpu_percent` win |
| 3.48.2 | 2018-11-18 | `dockerContainerStats()` fixed issue `cpu_percent`, win exec |
| 3.48.1 | 2018-11-17 | `docker...()` fixed issue parsing docker socket JSON |
| 3.48.0 | 2018-11-17 | `diskLayout()` better interface detection (WIN), `osInfo()` added build, serial |
| 3.47.0 | 2018-11-06 | `versions()` added docker, postfix |
| 3.46.0 | 2018-11-05 | fixed issue `versions()`, added system openssl version |
| 3.45.10 | 2018-11-03 | fixed issue `battery()`, modified `package.json` - files |
| 3.45.9 | 2018-10-22 | fixed node 4 incompatibility |
| 3.45.8 | 2018-10-22 | `system()` fix Raspberry Pi detection |
| 3.45.7 | 2018-10-05 | fixed typos |
| 3.45.6 | 2018-09-12 | `mem()` bug parsing linux in other languages |
| 3.45.5 | 2018-09-07 | `diskLayout()` tiny bug S.M.A.R.T status windows |
| 3.45.4 | 2018-09-06 | added icon to README.md |
| 3.45.3 | 2018-09-06 | `diskLayout()` optimized media type detection (HD, SSD) on Windows |
| 3.45.2 | 2018-09-05 | updated imags shields icons |
| 3.45.1 | 2018-09-05 | updated documentation |
| 3.45.0 | 2018-09-04 | `diskLayout()` added smartStatus |
| 3.44.2 | 2018-08-28 | added code quality badges |
| 3.44.1 | 2018-08-28 | code cleanup |
| 3.44.0 | 2018-08-25 | `battery()` bugfix & added type, model, manufacturer, serial |
| 3.43.0 | 2018-08-25 | `cpuCurrentspeed()` added cpu speed for all cores |
| 3.42.10 | 2018-08-25 | `processes()` optimized start time parsing |
| 3.42.9 | 2018-08-08 | `cpuTemperature()` optimized parsing |
| 3.42.8 | 2018-08-03 | updated docs |
| 3.42.7 | 2018-08-03 | `processes()` optimized parsing ps name |
| 3.42.6 | 2018-08-03 | `processes()` bugfix parsing ps linux |
| 3.42.5 | 2018-08-03 | `processes()` bugfix parsing ps linux |
| 3.42.4 | 2018-07-09 | `cpuTemperature()` bugfix parsing negative values |
| 3.42.3 | 2018-07-05 | `services()` bugfix not finding services with capital letters |
| 3.42.2 | 2018-07-03 | `users()` optimized results if lack of permissions |
| 3.42.1 | 2018-07-03 | `versions()` bugfix git version macOS |
| 3.42.0 | 2018-06-01 | `processes()` added parent process PID |
| 3.41.4 | 2018-05-28 | windows exec WMIC path detection (windows) in try catch |
| 3.41.3 | 2018-05-13 | improved SunOS support `getStaticData()`, `getDynamicData()` |
| 3.41.2 | 2018-05-13 | bugfix `system()` and `flags()` Raspberry Pi |
| 3.41.1 | 2018-05-11 | updated docs |
| 3.41.0 | 2018-05-11 | `system()` Raspberry Pi bugfix and extended detection, added partial `SunOS` support |
| 3.40.1 | 2018-05-10 | bugfix `system().sku` (windows) |
| 3.40.0 | 2018-04-29 | extended `versions()` (php, redis, mongodb) |
| 3.39.0 | 2018-04-29 | added `versions().mysql` and `versions().nginx`, starting `SunOS` support (untested) |
| 3.38.0 | 2018-04-06 | added `battery().acconnected` |
| 3.37.12 | 2018-04-05 | another optimization `battery().ischarging` for macOS |
| 3.37.11 | 2018-04-05 | another optimization `battery().ischarging` for macOS |
| 3.37.10 | 2018-04-05 | `battery().ischarging` optimized for macOS |
| 3.37.9 | 2018-04-03 | optimized `processes()`, bugfix `networkInterfaceDefault()` |
| 3.37.8 | 2018-03-25 | optimized `networkDefaultInterface()` detection, fixed network `operstate` MacOS |
| 3.37.7 | 2018-03-13 | celebrating 4th birthday |
| 3.37.6 | 2018-03-12 | updated docs: fixed `diskLayout`and `mamlayout` |
| 3.37.5 | 2018-03-12 | added support for `ip` instead of `ifconfig` |
| 3.37.4 | 2018-02-22 | bugfix windows `processes()`, `disklayout()` |
| 3.37.3 | 2018-02-19 | added windows exec `windowsHide` option |
| 3.37.2 | 2018-02-15 | fixed bug `battery().percent` for macOS |
| 3.37.1 | 2018-02-13 | fixed bug `battery().ischarging` for macOS |
| 3.37.0 | 2018-02-11 | extended FreeBSD support `networkStats()` |
| 3.36.0 | 2018-02-11 | extended FreeBSD support `networkConnections()` |
| 3.35.0 | 2018-02-11 | extended FreeBSD support `processLoad()` |
| 3.34.1 | 2018-02-11 | updated docs |
| 3.34.0 | 2018-02-10 | first partial FreeBSD support |
| 3.33.15 | 2018-01-21 | optimized OSX battery |
| 3.33.14 | 2018-01-17 | bugfix `diskLayout()` (Windows) |
| 3.33.13 | 2018-01-12 | bugfix `memLayout()` (Windows) |
| 3.33.12 | 2017-12-25 | fixed typos |
| 3.33.11 | 2017-12-17 | updated docs |
| 3.33.10 | 2017-12-14 | bugfix WMIC path detection (windows) blockDevice parse (Windows 7) |
| 3.33.9 | 2017-12-14 | bugfix WMIC path detection (windows) not found (Windows) |
| 3.33.8 | 2017-12-02 | bugfix diskLayout().size (OSX) |
| 3.33.7 | 2017-11-28 | bugfix diskLayout().size |
| 3.33.6 | 2017-11-16 | bugfix diskLayout().size |
| 3.33.5 | 2017-11-09 | code cleanup |
| 3.33.4 | 2017-11-09 | bugfix graphics controller win (bytes) |
| 3.33.3 | 2017-11-08 | bugfix cpu speed arm - type |
| 3.33.2 | 2017-11-08 | bugfix cpu speed arm |
| 3.33.1 | 2017-11-07 | improved bios and main board information |
| 3.33.0 | 2017-11-07 | added bios and main board information |
| 3.32.4 | 2017-11-02 | AMD cpu base frequencies table also for windows |
| 3.32.3 | 2017-11-02 | code cleanup, AMD cpu base frequencies table |
| 3.32.2 | 2017-11-01 | bugfix JSON.parse error `blockDevices()` |
| 3.32.1 | 2017-10-23 | updated docs |
| 3.32.0 | 2017-10-23 | extended `memLayout()` - added manufacturer |
| 3.31.4 | 2017-10-21 | updated `README.md` |
| 3.31.3 | 2017-10-21 | bugfix `graphics()`, fixed typo `README.md` |
| 3.31.2 | 2017-10-16 | bugfix `graphics()` vendor and model parsing linux VGA/3D |
| 3.31.1 | 2017-10-16 | bugfix `graphics()` vendor and model parsing linux |
| 3.31.0 | 2017-10-15 | extended windows support `cpuFlags()` (partially) |
| 3.30.6 | 2017-10-05 | updated community profile |
| 3.30.5 | 2017-10-05 | bugfix `users()` - parsing values on windows |
| 3.30.4 | 2017-10-03 | bugfix `cpuTemperature()` - parsing values on windows |
| 3.30.3 | 2017-10-03 | bugfix `cpuTemperature()` - max value on windows |
| 3.30.2 | 2017-09-26 | bugfix `networkInterfaces()` - optimized ip6 address selection |
| 3.30.1 | 2017-09-21 | bugfix/typo `inetChecksite()` |
| 3.30.0 | 2017-09-21 | extended `versions()` (added `yarn`, `gulp`, `grunt`, `tsc`, `git`) |
| 3.29.0 | 2017-09-15 | extended windows support `services()`, optimized `diskLayout()` (OSX), bugfixes |
| 3.28.0 | 2017-09-14 | extended windows support `processes()` |
| 3.27.1 | 2017-09-13 | updated Raspberry version detection `system()` (Pi 3, Zero) |
| 3.27.0 | 2017-09-12 | added raw data to `currentLoad()`, fixed `networkInterfaces()` MAC problem node 8.x |
| 3.26.2 | 2017-09-01 | removed redundant code |
| 3.26.1 | 2017-08-23 | fixed `cpu().speed` windows / AMD, updated docs |
| 3.26.0 | 2017-08-21 | extended `getDynamicData()` (windows), updated docs |
| 3.25.1 | 2017-08-07 | updated docs |
| 3.25.0 | 2017-08-07 | improved windows support `networkStats()`, `cpuCache()`, bug fix `getStaticData()` |
| 3.24.0 | 2017-08-05 | extended windows support `networkStats()`, `networkConnections()` |
| 3.23.7 | 2017-07-11 | bug fix `diskLayout()` |
| 3.23.6 | 2017-07-11 | added `cpuFlags()` to `getStaticData()`, bug fix `graphics()` (Win) |
| 3.23.5 | 2017-06-29 | bug fix `inetChecksite()` |
| 3.23.4 | 2017-06-24 | bug fix `getDynamicData(), getAllData() - mem` |
| 3.23.3 | 2017-06-23 | updated docs |
| 3.23.2 | 2017-06-23 | bug fix `battery` (windows) |
| 3.23.1 | 2017-06-22 | updated docs |
| 3.23.0 | 2017-06-22 | added `memLayout`, `diskLayout`, extended windows support (`inetChecksite`)|
| 3.22.0 | 2017-06-19 | extended windows support (`users`, `inetLatency`) |
| 3.21.0 | 2017-06-18 | extended time (timezone), extended windows support (battery, getAll...) |
| 3.20.1 | 2017-06-17 | updated docs |
| 3.20.0 | 2017-06-16 | extend WIN support (cpu, cpuCache, cpuCurrentspeed, mem, networkInterfaces, docker) |
| 3.19.0 | 2017-06-12 | OSX temperature now an optional dependency |
| 3.18.0 | 2017-05-27 | extended `cpu` info (vendor, family, model, stepping, revision, cache, speedmin/max) |
| 3.17.3 | 2017-04-29 | minor fix (blockDevices data array, Windows) |
| 3.17.2 | 2017-04-24 | minor fix (removed console.log) |
| 3.17.1 | 2017-04-23 | fixed bugs fsSize(win), si.processes (command), si.osinfo(win) |
| 3.17.0 | 2017-02-19 | windows support for some first functions, extended process list (linux)|
| 3.16.0 | 2017-01-19 | blockDevices: added removable attribute + fix |
| 3.15.1 | 2017-01-17 | minor cpuTemperature fix (OSX) |
| 3.15.0 | 2017-01-15 | added cpuTemperature also for OSX |
| 3.14.0 | 2017-01-14 | added currentLoad per cpu/core, cpu cache and cpu flags |
| 3.13.0 | 2016-11-23 | added shell (returns standard shell) |
| 3.12.0 | 2016-11-17 | refactoring and extended currentLoad |
| 3.11.2 | 2016-11-16 | blockDevices: improved for older lsblk versions |
| 3.11.1 | 2016-11-16 | fixed small bug in blockDevices |
| 3.11.0 | 2016-11-15 | blockDevices for OSX and extended blockDevices |
| 3.10.2 | 2016-11-14 | bug fix fsSize on OSX |
| 3.10.1 | 2016-11-14 | optimization fsStats, disksIO, networkStats |
| 3.10.0 | 2016-11-12 | added blockDevices, fixed fsSize, added file system type |
| 3.9.0 | 2016-11-11 | added MAC address to networkInterfaces, fixed currentLoad |
| 3.8.1 | 2016-11-04 | updated docs |
| 3.8.0 | 2016-11-04 | added dockerContainerProcesses |
| 3.7.1 | 2016-11-03 | code refactoring |
| 3.7.0 | 2016-11-02 | extended docker stats, and no longer relying on curl |
| 3.6.0 | 2016-09-14 | added versions (kernel, ssl, node, npm, pm2, ...) |
| 3.5.1 | 2016-09-14 | bugfix graphics info |
| 3.5.0 | 2016-09-14 | added graphics info (controller, display) |
| 3.4.4 | 2016-09-02 | tiny fixes system.model, getDefaultNetworkInterface |
| 3.4.3 | 2016-09-02 | tiny bug fix fsStats, disksIO OSX |
| 3.4.2 | 2016-09-01 | improved default network interface |
| 3.4.1 | 2016-08-30 | updated docs |
| 3.4.0 | 2016-08-30 | rewritten processes current cpu usage |
| 3.3.0 | 2016-08-24 | process list added to processes |
| 3.2.1 | 2016-08-19 | updated docs, improvement system |
| 3.2.0 | 2016-08-19 | added battery information |
| 3.1.1 | 2016-08-18 | improved system and os detection (vm, ...), bugfix disksIO |
| 3.1.0 | 2016-08-18 | added Docker stats |
| 3.0.1 | 2016-08-17 | Bug-Fix disksIO, users, updated docs |
| 3.0.0 | 2016-08-03 | new major version 3.0 |
| 2.0.5 | 2016-03-02 | changed .gitignore |
| 2.0.4 | 2016-02-22 | tiny correction - removed double quotes CPU brand, ... |
| 2.0.3 | 2016-02-22 | optimized cpuCurrentspeed |
| 2.0.2 | 2016-02-22 | added CoreOS identification |
| 2.0.1 | 2016-01-07 | minor patch |
| 2.0.0 | 2016-01-07 | new major version 2.0 |
| 1.0.7 | 2015-11-27 | fixed: si.network_speed() |
| 1.0.6 | 2015-09-17 | fixed: si.users() |
| 1.0.5 | 2015-09-14 | updated dependencies |
| 1.0.4 | 2015-07-18 | updated docs |
| 1.0.3 | 2015-07-18 | bugfix cpu cores |
| 1.0.2 | 2015-07-18 | bugfix cpu_currentspeed, cpu_temperature |
| 1.0.1 | 2015-07-18 | documentation update |
| 1.0.0 | 2015-07-18 | bug-fixes, version bump, published as npm component |
| 0.0.3 | 2014-04-14 | bug-fix (cpu_speed) |
| 0.0.2 | 2014-03-14 | Optimization FS-Speed & CPU current speed |
| 0.0.1 | 2014-03-13 | initial release |
### Major (breaking) Changes - Version 3
- works only with [node.js][nodejs-url] **v4.0.0** and above (using now internal ES6 promise function, arrow functions, ...)
- **Promises**. As you can see in the documentation, you can now also use it in a promise oriented way. But callbacks are still supported.
- **Async/Await**. Due to the promises support, systeminformation also works perfectly with the `async/await` pattern (available in [node.js][nodejs-url] **v7.6.0** and above). See example in the docs.
- `cpuCurrentspeed`: now returns an object with current minimal, maximal and average CPU frequencies of all cores.
- `mem`: now supports also newer versions of `free` (Version 3.3.10 and above); extended information `avaliable` (potentially available memory)
- `fsStats`: added information sum bytes read + write (tx) and sum transfer rate/sec (tx_sec)
- `networkInterfaces`: now providing one more detail: internal - true if this is an internal interface like "lo"
- `networkConnections`: instead of only counting sockets, you now get an array of objects with connection details for each socket (protocol, local and peer address, state)
- `users`: now provides an array of objects with users online including detailed session information (login date/time, ip address, terminal, command)
- `inetLatency`: now you can provide a host against which you want to test latency (default is 8.8.8.8)
- `getDynamicData`: changed order of parameters (callback - if provided - is now the last one): `getDynamicData(srv, network, callback)`
- `getAllData`: changed order of parameters (callback - if provided - is now the last one): `getAllData(srv, network, callback)`
New Functions
- FreeBSD support: for some basic functions (new in version 3.34 ff)
- `diskLayout`: returns hard disk layout (new in version 3.23)
- `memLayout`: returns memory chip layout (new in version 3.23)
- Windows support: for some basic functions (new in version 3.17 ff)
- `cpuCache`: returns CPU cache (L1, L2, L3) sizes (new in version 3.14)
- `cpuFlags`: returns CPU flags (new in version 3.14)
- `currentLoad.cpus`: returns current load per cpu/core in an array (new in version 3.14)
- `shell`: returns standard shell e.g. /bin/bash (new in version 3.13)
- `blockDevices`: returns array of block devices like disks, partitions, raids, roms (new in version 3.10)
- `dockerContainerProcesses`: returns processes for a specific docker container (new in version 3.8)
- `versions`: returns object of versions - kernel, ssl, node, npm, ...(new in version 3.6)
- `graphics`: returns arrays of graphics controllers and displays (new in version 3.5)
- `networkInterfaceDefault`: returns default network interface (new in version 3.4)
- `processes`: now returns also a process list with all process details (new in version 3.3)
- `battery`: retrieves battery status and charging level (new in version 3.2)
- `dockerContainers`: returns a list of all docker containers (new in version 3.1)
- `dockerContainerStats`: returns statistics for a specific docker container (new in version 3.1)
- `dockerAll`: returns a list of all docker containers including their stats (new in version 3.1)
- `disksIO`: returns overall diskIO and IOPS values for all mounted volumes (new in version 3.0)
Bug Fixes / improvements
- improvement `cpuTemperature` - works now also on Raspberry Pi
- bugfix `disksIO` - on OSX read and write got mixed up
- several bug fixes (like assess errors in `cpuCurrentspeed`, potentially incorrect results in `users`, ...)
- testet on even more platforms and linux distributions
**Be aware**, that the new version 3.x is **NOT fully backward compatible** to version 2.x ...
### Major (breaking) Changes - Version 2
There had been a lot of changes in version 2 of systeminformation! Here is a quick overview (for those who come from version 1):
New Functions
- `version`: returns systeminformation version (semver) of this library
- `system`: hardware info (manufacturer, product/model name, version, serial, uuid)
- `networkConnections`: number of active connections
- `inetLatency`: latency in ms to external resource (internet)
- `getStaticData`: returns on json object with static data at once (OS, CPU, Network Interfaces - they should not change until restarted)
- `getDynamicData`: returns on json object with all dynamic data at once (e.g. for monitoring agents)
- `getAllData`: returns on json object with all data (static and dynamic) at once
Renamed Functions (now all camelCase)
- `osinfo`: renamed to `osInfo`
- `cpu_currentspeed`: renamed to `cpuCurrentspeed`
- `cpu_temperature`: renamed to `cpuTemperature`
- `fs_size`: renamed to `fsSize`
- `fs_speed`: renamed to `fsStats`
- `network_interfaces`: renamed to `networkInterfaces`
- `network_speed`: renamed to `networkStats`
- `network_connections`: renamed to `networkConnections`
- `currentload`: renamed to `currentLoad`
- `fullload`: renamed to `fullLoad`
- `processload`: renamed to `processLoad`
- `checksite`: renamed to `inetChecksite`
Function Changes
- `cpu_temperature`/`cpuTemperature`: -1 is new default (and indicates that non sensors are installed)
- `cpu_temperature`/`cpuTemperature`: new result `max` which returns max temperature of all cores
- `cpu_currentspeed`/`cpuCurrentspeed`: now in GHz
- `cpu`: splitted `manufacturer` (e.g. Intel) and `brand` (e.g. Core 2 Duo)
- `network_speed`/`networkStats`: now better support for OS X (also support for `operstate`)
- `network_speed`/`networkStats`: overall received and transferred bytes (rx, tx)
- `mem`: now better support for OS X (also support for `swaptotal`, `swapused`, `swapfree`)
- `fs_size`/`fsSize`: use-values now in % (0 - 100% instead of 0 - 1)
- `fs_speed`/`fsStats`: now also full support for OS X
- `checksite`/`inetChecksite`: new result structure - see command reference
- `checksite`/`inetChecksite`: ms (former `response_ms`): -1 if not ok
Other changes
- osx-temperature-sensor: now added as an optional dependency
- no more external dependencies: `request` is not longer needed
- where possible results are now integer or float values (instead of strings) because it is easier to calculate with numbers ;-)
[nodejs-url]: https://nodejs.org/en/
The MIT License (MIT)
Copyright (c) 2014-2019 Sebastian Hildebrandt
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<p align="center">
<a href="https://systeminformation.io/">
<img src="https://systeminformation.io/assets/logo_inv.png" alt="systeminformation logo" width="102" height="72">
</a>
</p>
<h3 align="center">systeminformation</h3>
<p align="center">
System and OS information library for node.js
<br>
<a href="https://systeminformation.io/"><strong>Explore Systeminformation docs »</strong></a>
<br>
<br>
<a href="https://github.com/sebhildebrandt/systeminformation/issues/new?template=bug_report.md">Report bug</a>
·
<a href="https://github.com/sebhildebrandt/systeminformation/issues/new?template=feature_request.md&labels=feature">Request feature</a>
·
<a href="https://github.com/sebhildebrandt/systeminformation/blob/master/CHANGELOG.md">Changelog</a>
</p>
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Git Issues][issues-img]][issues-url]
[![Closed Issues][closed-issues-img]][closed-issues-url]
[![deps status][daviddm-img]][daviddm-url]
[![Code Quality: Javascript][lgtm-badge]][lgtm-badge-url]
[![Total alerts][lgtm-alerts]][lgtm-alerts-url]
[![Caretaker][caretaker-image]][caretaker-url]
[![MIT license][license-img]][license-url]
**2019-03-12** - 5th birthday of systeminformation. This is amazing. Started as a small projekt just for myself, it now has > 8,000 lines of code, > 200 versions published, up to 100,000 downloads per month, > 1 Mio downloads overall. Thank you to all who contributed to this project!
## New Version 4.0
This next major version release 4.0 comes with several optimizations and changes:
- new systeminformation website with better documentation and examples [systeminformation.io][systeminformation-url]
- added typescript definitions
- reworked network section: this will now return more information and allows to get networkStats for more than one interface at once.
- dockerContainerStats for multiple containers or all containers at once
- optimized graphics controller and display detection
- added wifiNetworks to get available wifi networks
- added vboxInfo to get detailed vm information
- added chassis information
- better Raspberry-PI detection
- lot of minor improvements
Breaking Changes: you will see some minor breaking changes. Read the [detailed changelog][changelog-url].
## Quick Start
Lightweight collection of 40+ functions to retrieve detailed hardware, system and OS information.
- simple to use
- get detailed information about system, cpu, baseboard, battery, memory, disks/filesystem, network, docker, software, services and processes
- supports Linux, macOS, partial Windows, FreeBSD, OpenBSD, NetBSD and SunOS support
- no npm dependencies (for production)
### Installation
```bash
$ npm install systeminformation --save
```
### Usage
All functions (except `version` and `time`) are implemented as asynchronous functions. Here a small example how to use them:
```js
const si = require('systeminformation');
// promises style - new since version 3
si.cpu()
.then(data => console.log(data))
.catch(error => console.error(error));
```
**Callback, Promises, Awync Await**
## News and Changes
### Latest Activity
(last 7 major and minor version releases)
- Version 4.14.0: `processes()` added process path and params
- Version 4.13.0: `networkConnections()` added PID, process
- Version 4.12.0: `networkInterfaces()` added property virtual
- Version 4.11.0: `wifiNetworks()` added available wifi networks
- Version 4.10.0: `graphics()` added windows multiple display support, added display size, connection, ...
- Version 4.9.0: `graphics()` added vendor, refresh rate, current resolution
- Version 4.8.0: added `vboxInfo()` detailed virtual box info
- ...
You can find all changes here: [detailed changelog][changelog-url]
## Core concept
[Node.js][nodejs-url] comes with some basic OS information, but I always wanted a little more. So I came up to write this little library. This library is still work in progress. It is supposed to be used as a backend/server-side library (will definilely not work within a browser). It requires node.js version 4.0 and above.
I was able to test it on several Debian, Raspbian, Ubuntu distributions as well as macOS (Mavericks, Yosemite, El Captain, Sierra, High Sierra, Mojave) and some Windows 7, Windows 10, FreeBSD, OpenBSD, NetBSD and SunOS machines. Not all functions are supported on all operating systems. Have a look at the function reference in the docs to get further details.
If you have comments, suggestions & reports, please feel free to contact me!
I also created a nice little command line tool called [mmon][mmon-github-url] (micro-monitor) for Linux and macOS, also available via [github][mmon-github-url] and [npm][mmon-npm-url]
## Reference
### Function Reference and OS Support
#### 1. General
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.version() | : string | X | X | X | X | X | lib version (no callback/promise) |
| si.time() | {...} | X | X | X | X | X | (no callback/promise) |
| | current | X | X | X | X | X | local (server) time |
| | uptime | X | X | X | X | X | uptime |
| | timezone | X | X | X | X | X | e.g. GMT+0200 |
| | timezoneName | X | X | X | X | X | e.g. CEST |
#### 2. System (HW)
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.system(cb) | {...} | X | X | X | X | | hardware information |
| | manufacturer | X | X | X | X | | e.g. 'MSI' |
| | model | X | X | X | X | | model/product e.g. 'MS-7823' |
| | version | X | X | X | X | | version e.g. '1.0' |
| | serial | X | X | X | X | | serial number |
| | uuid | X | X | X | X | | UUID |
| | sku | X | X | X | X | | SKU number |
| si.bios(cb) | {...} | X | X | X | X | | bios information |
| | vendor | X | X | X | X | | e.g. 'AMI' |
| | version | X | X | | X | | version |
| | releaseDate | X | X | | X | | release date |
| | revision | X | X | | X | | revision |
| si.baseboard(cb) | {...} | X | X | X | X | | baseboard information |
| | manufacturer | X | X | X | X | | e.g. 'ASUS' |
| | model | X | X | X | X | | model / product name |
| | version | X | X | X | X | | version |
| | serial | X | X | X | X | | serial number |
| | assetTag | X | X | X | X | | asset tag |
| si.chassis(cb) | {...} | X | X | X | X | | chassis information |
| | manufacturer | X | X | X | X | | e.g. 'MSI' |
| | model | X | X | X | X | | model / product name |
| | type | X | X | X | X | | model / product name |
| | version | X | X | X | X | | version |
| | serial | X | X | X | X | | serial number |
| | assetTag | X | X | X | X | | asset tag |
| | sku | | | | X | | SKU number |
#### 3. CPU
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.cpu(cb) | {...} | X | X | X | X | | CPU information|
| | manufacturer | X | X | X | X | | e.g. 'Intel(R)' |
| | brand | X | X | X | X | | e.g. 'Core(TM)2 Duo' |
| | speed | X | X | X | X | | in GHz e.g. '3.40' |
| | speedmin | X | | X | X | | in GHz e.g. '0.80' |
| | speedmax | X | X | X | X | | in GHz e.g. '3.90' |
| | cores | X | X | X | X | | # cores |
| | physicalCores | X | X | X | X | | # physical cores |
| | processors | X | X | X | X | | # processors |
| | socket | X | X | | X | | socket type e.g. "LGA1356" |
| | vendor | X | X | X | X | | vendor ID |
| | family | X | X | X | X | | processor family |
| | model | X | X | X | X | | processor model |
| | stepping | X | X | X | X | | processor stepping |
| | revision | X | | X | X | | revision |
| | voltage | | X | | | | voltage |
| | cache | X | X | X | X | | cache in bytes (object) |
| | cache.l1d | X | X | X | X | | L1D (data) size |
| | cache.l1i | X | X | X | X | | L1I (instruction) size |
| | cache.l2 | X | X | X | X | | L2 size |
| | cache.l3 | X | X | X | X | | L3 size |
| si.cpuFlags(cb) | : string | X | X | X | X | | CPU flags|
| si.cpuCache(cb) | {...} | X | X | X | X | | CPU cache sizes |
| | l1d | X | X | X | X | | L1D size |
| | l1i | X | X | X | X | | L1I size |
| | l2 | X | X | X | X | | L2 size |
| | l3 | X | X | X | X | | L3 size |
| si.cpuCurrentspeed(cb) | {...} | X | X | X | X | X | current CPU speed (in GHz)|
| | avg | X | X | X | X | X | avg CPU speed (all cores) |
| | min | X | X | X | X | X | min CPU speed (all cores) |
| | max | X | X | X | X | X | max CPU speed (all cores) |
| | cores | X | X | X | X | X | CPU speed per core (array) |
| si.cpuTemperature(cb) | {...} | X | X | X* | X | | CPU temperature (if supported) |
| | main | X | X | X | X | | main temperature (avg) |
| | cores | X | X | X | X | | array of temperatures |
| | max | X | X | X | X | | max temperature |
#### 4. Memory
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.mem(cb) | {...} | X | X | X | X | X | Memory information (in bytes)|
| | total | X | X | X | X | X | total memory in bytes |
| | free | X | X | X | X | X | not used in bytes |
| | used | X | X | X | X | X | used (incl. buffers/cache) |
| | active | X | X | X | X | X | used actively (excl. buffers/cache) |
| | buffcache | X | X | X | | X | used by buffers+cache |
| | available | X | X | X | X | X | potentially available (total - active) |
| | swaptotal | X | X | X | X | X | |
| | swapused | X | X | X | X | X | |
| | swapfree | X | X | X | X | X | |
| si.memLayout(cb) | [{...}] | X | X | X | X | | Memory Layout (array) |
| | [0].size | X | X | X | X | | size in bytes |
| | [0].bank | X | X | | X | | memory bank |
| | [0].type | X | X | X | X | | memory type |
| | [0].clockSpeed | X | X | X | X | | clock speed |
| | [0].formFactor | X | X | | X | | form factor |
| | [0].manufacturer | X | X | X | X | | manufacturer |
| | [0].partNum | X | X | X | X | | part number |
| | [0].serialNum | X | X | X | X | | serial number |
| | [0].voltageConfigured | X | X | | X | | voltage conf. |
| | [0].voltageMin | X | X | | X | | voltage min |
| | [0].voltageMax | X | X | | X | | voltage max |
#### 5. Battery
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.battery(cb) | {...} | X | X | X | X | | battery information |
| | hasbattery | X | X | X | X | | indicates presence of battery |
| | cyclecount | X | | X | | | numbers of recharges |
| | ischarging | X | X | X | X | | indicates if battery is charging |
| | maxcapacity | X | | X | X | | max capacity of battery |
| | currentcapacity | X | | X | X | | current capacity of battery |
| | percent | X | X | X | X | | charging level in percent |
| | timeremaining | X | | X | | | minutes left (if discharging) |
| | acconnected | X | X | X | X | | AC connected |
| | type | X | | X | | | battery type |
| | model | X | | X | | | model |
| | manufacturer | X | | X | | | manufacturer |
| | serial | X | | X | | | battery serial |
* See known issues if you have problem with macOS temperature or windows temperature
#### 6. Graphics
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.graphics(cb) | {...} | X | | X | X | | arrays of graphics controllers and displays |
| | controllers[]| X | | X | X | | graphics controllers array |
| | ...[0].model | X | | X | X | | graphics controller model |
| | ...[0].vendor | X | | X | X | | e.g. ATI |
| | ...[0].bus | X | | X | X | | on which bus (e.g. PCIe) |
| | ...[0].vram | X | | X | X | | VRAM size (in MB) |
| | ...[0].vramDynamic | X | | X | X | | true if dynamicly allocated ram |
| | displays[] | X | | X | X | | monitor/display array |
| | ...[0].vendor | | | | X | | monitor/display vendor |
| | ...[0].model | X | | X | X | | monitor/display model |
| | ...[0].main | X | | X | X| | true if main monitor |
| | ...[0].builtin | X | | X | | | true if built in monitor |
| | ...[0].connection | X | | X | X | | e.g. DisplayPort or HDMI |
| | ...[0].sizex | X | | X | X | | size in mm horizontal |
| | ...[0].sizey | X | | X | X | | size in mm vertical |
| | ...[0].pixeldepth | X | | X | X | | color depth in bits |
| | ...[0].resolutionx | X | | X | X | | pixel horizontal |
| | ...[0].resolutiony | X | | X | X | | pixel vertical |
| | ...[0].currentResX | X | | X | X | | current pixel horizontal |
| | ...[0].currentResY | X | | X | X | | current pixel vertical |
| | ...[0].positionX | | | | X | | display position X |
| | ...[0].positionY | | | | X | | display position Y |
| | ...[0].currentRefreshRate | X | | X | X | | current pixel vertical |
#### 7. Operating System
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.osInfo(cb) | {...} | X | X | X | X | X | OS information |
| | platform | X | X | X | X | X | 'Linux', 'Darwin', 'Windows' |
| | distro | X | X | X | X | X | |
| | release | X | X | X | X | X | |
| | codename | | | X | | | |
| | kernel | X | X | X | X | X | kernel release - same as os.release() |
| | arch | X | X | X | X | X | same as os.arch() |
| | hostname | X | X | X | X | X | same as os.hostname() |
| | codepage | X | X | X | X | | OS build version |
| | logofile | X | X | X | X | X | e.g. 'apple', 'debian', 'fedora', ... |
| | serial | X | X | X | X | | OS/Host serial number |
| | build | X | | X | X | | OS build version |
| | servicepack | | | | X | | service pack version |
| si.uuid(cb) | {...} | X | X | X | X | X | object of several UUIDs |
| | os | X | X | X | X | | os specific UUID |
| si.versions(cb) | {...} | X | X | X | X | X | version information (kernel, ssl, node, ...) |
| si.shell(cb) | : string | X | X | X | | | standard shell |
| si.users(cb) | [{...}] | X | X | X | X | X | array of users online |
| | [0].user | X | X | X | X | X | user name |
| | [0].tty | X | X | X | X | X | terminal |
| | [0].date | X | X | X | X | X | login date |
| | [0].time | X | X | X | X | X | login time |
| | [0].ip | X | X | X | | X | ip address (remote login) |
| | [0].command | X | X | X | | X | last command or shell |
#### 8. Current Load, Processes & Services
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.currentLoad(cb) | {...} | X | | X | X | X | CPU-Load |
| | avgload | X | | X | X | X | average load |
| | currentload | X | | X | X | X | CPU load in % |
| | currentload_user | X | | X | X | X | CPU load user in % |
| | currentload_system | X | | X | X | X | CPU load system in % |
| | currentload_nice | X | | X | X | X | CPU load nice in % |
| | currentload_idle | X | | X | X | X | CPU load idle in % |
| | currentload_irq | X | | X | X | X | CPU load system in % |
| | raw_currentload... | X | | X | X | X | CPU load raw values (ticks) |
| | cpus[] | X | | X | X | X | current loads per CPU in % + raw ticks |
| si.fullLoad(cb) | : integer | X | | X | X | | CPU full load since bootup in % |
| si.processes(cb) | {...} | X | X | X | X | X | # running processes |
| | all | X | X | X | X | X | # of all processes |
| | running | X | X | X | X | X | # of all processes running |
| | blocked | X | X | X | X | X | # of all processes blocked |
| | sleeping | X | X | X | X | X | # of all processes sleeping |
| | unknown | | | | X | | # of all processes unknown status |
| | list[] | X | X | X | X | X | list of all processes incl. details |
| | ...[0].pid | X | X | X | X | X | process PID |
| | ...[0].parentPid | X | X | X | X | X | parent process PID |
| | ...[0].name | X | X | X | X | X | process name |
| | ...[0].pcpu | X | X | X | X | X | process % CPU usage |
| | ...[0].pcpuu | X | X | | X | | process % CPU usage (user) |
| | ...[0].pcpus | X | X | | X | | process % CPU usage (system) |
| | ...[0].pmem | X | X | X | X | X | process memory % |
| | ...[0].priority | X | X | X | X | X | process priotity |
| | ...[0].mem_vsz | X | X | X | X | X | process virtual memory size |
| | ...[0].mem_rss | X | X | X | X | X | process mem resident set size |
| | ...[0].nice | X | X | X | | X | process nice value |
| | ...[0].started | X | X | X | X | X | process start time |
| | ...[0].state | X | X | X | X | X | process state (e.g. sleeping) |
| | ...[0].tty | X | X | X | | X | tty from which process was started |
| | ...[0].user | X | X | X | | X | user who started process |
| | ...[0].command | X | X | X | X | X | process starting command |
| | ...[0].params | X | X | X | | X | process params |
| | ...[0].path | X | X | X | X | X | process path |
| | proc | X | X | X | X | | process name |
| | pid | X | X | X | X | | PID |
| | pids | X | X | X | X | | additional pids |
| | cpu | X | X | X | X | | process % CPU |
| | mem | X | X | X | X | | process % MEM |
| si.services('mysql, apache2', cb) | [{...}] | X | X | X | X | | pass comma separated string of services<br>pass "*" for ALL services (linux/win only) |
| | [0].name | X | X | X | X | | name of service |
| | [0].running | X | X | X | X | | true / false |
| | [0].startmode | | | | X | | manual, automatic, ... |
| | [0].pids | X | X | X | | | pids |
| | [0].pcpu | X | X | X | | | process % CPU |
| | [0].pmem | X | X | X | | | process % MEM |
#### 9. File System
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.diskLayout(cb) | [{...}] | X | | X | X | | physical disk layout (array) |
| | [0].device | X | | X | | | e.g. /dev/sda |
| | [0].type | X | | X | X | | HD, SSD, NVMe |
| | [0].name | X | | X | X | | disk name |
| | [0].vendor | X | | | X | | vendor/producer |
| | [0].size | X | | X | X | | size in bytes |
| | [0].bytesPerSector | | | | X | | bytes per sector |
| | [0].totalCylinders | | | | X | | total cylinders |
| | [0].totalHeads | | | | X | | total heads |
| | [0].totalSectors | | | | X | | total sectors |
| | [0].totalTracks | | | | X | | total tracks |
| | [0].tracksPerCylinder | | | | X | | tracks per cylinder |
| | [0].sectorsPerTrack | | | | X | | sectors per track |
| | [0].firmwareRevision | X | | X | X | | firmware revision |
| | [0].serialNum | X | | X | X | | serial number |
| | [0].interfaceType | X | | | X | | SATA, PCIe, ... |
| | [0].smartStatus | X | | X | X | | S.M.A.R.T Status (see Known Issues) |
| si.blockDevices(cb) | [{...}] | X | | X | X | | returns array of disks, partitions,<br>raids and roms |
| | [0].name | X | | X | X | | name |
| | [0].type | X | | X | X | | type |
| | [0].fstype | X | | X | X | | file system type (e.g. ext4) |
| | [0].mount | X | | X | X | | mount point |
| | [0].size | X | | X | X | | size in bytes |
| | [0].physical | X | | X | X | | physical type (HDD, SSD, CD/DVD) |
| | [0].uuid | X | | X | X | | UUID |
| | [0].label | X | | X | X | | label |
| | [0].model | X | | X | | | model |
| | [0].serial | X | | | X | | serial |
| | [0].removable | X | | X | X | | serial |
| | [0].protocol | X | | X | | | protocol (SATA, PCI-Express, ...) |
| si.disksIO(cb) | {...} | X | | X | | | current transfer stats |
| | rIO | X | | X | | | read IOs on all mounted drives |
| | wIO | X | | X | | | write IOs on all mounted drives |
| | tIO | X | | X | | | write IOs on all mounted drives |
| | rIO_sec | X | | X | | | read IO per sec (* see notes) |
| | wIO_sec | X | | X | | | write IO per sec (* see notes) |
| | tIO_sec | X | | X | | | total IO per sec (* see notes) |
| | ms | X | | X | | | interval length (for per second values) |
| si.fsSize(cb) | [{...}] | X | X | X | X | | returns array of mounted file systems |
| | [0].fs | X | X | X | X | | name of file system |
| | [0].type | X | X | X | X | | type of file system |
| | [0].size | X | X | X | X | | sizes in bytes |
| | [0].used | X | X | X | X | | used in bytes |
| | [0].use | X | X | X | X | | used in % |
| | [0].mount | X | X | X | X | | mount point |
| si.fsOpenFiles(cb) | {...} | X | X | X | | | count max/allocated file descriptors |
| | max | X | X | X | | | max file descriptors |
| | allocated | X | X | X | | | current open files count |
| | available | X | X | X | | | count available |
| si.fsStats(cb) | {...} | X | | X | | | current transfer stats |
| | rx | X | | X | | | bytes read since startup |
| | wx | X | | X | | | bytes written since startup |
| | tx | X | | X | | | total bytes read + written since startup |
| | rx_sec | X | | X | | | bytes read / second (* see notes) |
| | wx_sec | X | | X | | | bytes written / second (* see notes) |
| | tx_sec | X | | X | | | total bytes reads + written / second |
| | ms | X | | X | | | interval length (for per second values) |
#### 10. Network related functions
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.networkInterfaces(cb) | [{...}] | X | X | X | X | X | array of network interfaces |
| | [0].iface | X | X | X | X | X | interface |
| | [0].ifaceName | X | X | X | X | X | interface name (differs on Windows) |
| | [0].ip4 | X | X | X | X | X | ip4 address |
| | [0].ip6 | X | X | X | X | X | ip6 address |
| | [0].mac | X | X | X | X | X | MAC address |
| | [0].internal | X | X | X | X | X | true if internal interface |
| | [0].virtual | X | X | X | X | X | true if virtual interface |
| | [0].operstate | X | | X | X | | up / down |
| | [0].type | X | | X | X | | wireless / wired |
| | [0].duplex | X | | X | | | duplex |
| | [0].mtu | X | | X | | | maximum transmission unit |
| | [0].speed | X | | X | X | | speed in MBit / s |
| | [0].carrierChanges | X | | | | | # changes up/down |
| si.networkInterfaceDefault(cb) | : string | X | X | X | X | X | get name of default network interface |
| si.networkStats(ifaces,cb) | [{...}] | X | X | X | X | | current network stats of given interfaces<br>iface list: space or comma separated<br>iface parameter is optional<br>defaults to first external network interface,<br />Pass '*' for all interfaces |
| | [0].iface | X | X | X | X | | interface |
| | [0].operstate | X | X | X | X | | up / down |
| | [0].rx_bytes | X | X | X | X | | received bytes overall |
| | [0].rx_dropped | X | X | X | X | | received dropped overall |
| | [0].rx_errors | X | X | X | X | | received errors overall |
| | [0].tx_bytes | X | X | X | X | | transferred bytes overall |
| | [0].tx_dropped | X | X | X | X | | transferred dropped overall |
| | [0].tx_errors | X | X | X | X | | transferred errors overall |
| | [0].rx_sec | X | X | X | X | | received bytes / second (* see notes) |
| | [0].tx_sec | X | X | X | X | | transferred bytes per second (* see notes) |
| | [0].ms | X | X | X | X | | interval length (for per second values) |
| si.networkConnections(cb) | [{...}] | X | X | X | X | | current network network connections<br>returns an array of all connections|
| | [0].protocol | X | X | X | X | | tcp or udp |
| | [0].localaddress | X | X | X | X | | local address |
| | [0].localport | X | X | X | X | | local port |
| | [0].peeraddress | X | X | X | X | | peer address |
| | [0].peerport | X | X | X | X | | peer port |
| | [0].state | X | X | X | X | | like ESTABLISHED, TIME_WAIT, ... |
| | [0].pid | X | X | X | X | | process ID |
| | [0].process | X | X | | | | process name |
| si.inetChecksite(url, cb) | {...} | X | X | X | X | X | response-time (ms) to fetch given URL |
| | url | X | X | X | X | X | given url |
| | ok | X | X | X | X | X | status code OK (2xx, 3xx) |
| | status | X | X | X | X | X | status code |
| | ms | X | X | X | X | X | response time in ms |
| si.inetLatency(host, cb) | : number | X | X | X | X | X | response-time (ms) to external resource<br>host parameter is optional (default 8.8.8.8)|
#### 11. Wifi networks
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.wifiNetworks(cb) | [{...}] | X | | X | X | | array of available wifi networks |
| | [0].ssid | X | | X | X | | Wifi network SSID |
| | [0].bssid | X | | X | X | | BSSID (mac) |
| | [0].mode | X | | | | | mode |
| | [0].channel | X | | X | X | | channel |
| | [0].frequency | X | | X | X | | frequengy in MHz |
| | [0].signalLevel | X | | X | X | | signal level in dB |
| | [0].quality | X | | X | X | | quaility in % |
| | [0].security | X | | X | X | | array e.g. WPA, WPA-2 |
| | [0].wpaFlags | X | | X | X | | array of WPA flags |
| | [0].rsnFlags | X | | | | | array of RDN flags |
#### 12. Docker
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.dockerInfo(cb) | {...} | X | X | X | X | X | returns general docker info |
| | id | X | X | X | X | X | Docker ID |
| | containers | X | X | X | X | X | number of containers |
| | containersRunning | X | X | X | X | X | number of running containers |
| | containersPaused | X | X | X | X | X | number of paused containers |
| | containersStopped | X | X | X | X | X | number of stopped containers |
| | images | X | X | X | X | X | number of images |
| | driver | X | X | X | X | X | driver (e.g. 'devicemapper', 'overlay2') |
| | memoryLimit | X | X | X | X | X | has memory limit |
| | swapLimit | X | X | X | X | X | has swap limit |
| | kernelMemory | X | X | X | X | X | has kernal memory |
| | cpuCfsPeriod | X | X | X | X | X | has CpuCfsPeriod |
| | cpuCfsQuota | X | X | X | X | X | has CpuCfsQuota |
| | cpuShares | X | X | X | X | X | has CPUShares |
| | cpuSet | X | X | X | X | X | has CPUShares |
| | ipv4Forwarding | X | X | X | X | X | has IPv4Forwarding |
| | bridgeNfIptables | X | X | X | X | X | has BridgeNfIptables |
| | bridgeNfIp6tables | X | X | X | X | X | has BridgeNfIp6tables |
| | debug | X | X | X | X | X | Debug on |
| | nfd | X | X | X | X | X | named data networking forwarding daemon |
| | oomKillDisable | X | X | X | X | X | out-of-memory kill disabled |
| | ngoroutines | X | X | X | X | X | number NGoroutines |
| | systemTime | X | X | X | X | X | docker SystemTime |
| | loggingDriver | X | X | X | X | X | logging driver e.g. 'json-file' |
| | cgroupDriver | X | X | X | X | X | cgroup driver e.g. 'cgroupfs' |
| | nEventsListener | X | X | X | X | X | number NEventsListeners |
| | kernelVersion | X | X | X | X | X | docker kernel version |
| | operatingSystem | X | X | X | X | X | docker OS e.g. 'Docker for Mac' |
| | osType | X | X | X | X | X | OSType e.g. 'linux' |
| | architecture | X | X | X | X | X | architecture e.g. x86_64 |
| | ncpu | X | X | X | X | X | number of CPUs |
| | memTotal | X | X | X | X | X | memory total |
| | dockerRootDir | X | X | X | X | X | docker root directory |
| | httpProxy | X | X | X | X | X | http proxy |
| | httpsProxy | X | X | X | X | X | https proxy |
| | noProxy | X | X | X | X | X | NoProxy |
| | name | X | X | X | X | X | Name |
| | labels | X | X | X | X | X | array of labels |
| | experimentalBuild | X | X | X | X | X | is experimental build |
| | serverVersion | X | X | X | X | X | server version |
| | clusterStore | X | X | X | X | X | cluster store |
| | clusterAdvertise | X | X | X | X | X | cluster advertise |
| | defaultRuntime | X | X | X | X | X | default runtime e.g. 'runc' |
| | liveRestoreEnabled | X | X | X | X | X | live store enabled |
| | isolation | X | X | X | X | X | isolation |
| | initBinary | X | X | X | X | X | init binary |
| | productLicense | X | X | X | X | X | product license |
| si.dockerContainers(all, cb) | [{...}] | X | X | X | X | X | returns array of active/all docker containers |
| | [0].id | X | X | X | X | X | ID of container |
| | [0].name | X | X | X | X | X | name of container |
| | [0].image | X | X | X | X | X | name of image |
| | [0].imageID | X | X | X | X | X | ID of image |
| | [0].command | X | X | X | X | X | command |
| | [0].created | X | X | X | X | X | creation time (unix) |
| | [0].started | X | X | X | X | X | creation time (unix) |
| | [0].finished | X | X | X | X | X | creation time (unix) |
| | [0].createdAt | X | X | X | X | X | creation date time string |
| | [0].startedAt | X | X | X | X | X | creation date time string |
| | [0].finishedAt | X | X | X | X | X | creation date time string |
| | [0].state | X | X | X | X | X | created, running, exited |
| | [0].ports | X | X | X | X | X | array of ports |
| | [0].mounts | X | X | X | X | X | array of mounts |
| si.dockerContainerStats(ids, cb) | [{...}] | X | X | X | X | X | statistics for specific containers<br>container IDs: space or comma separated,<br>pass '*' for all containers|
| | [0].id | X | X | X | X | X | Container ID |
| | [0].mem_usage | X | X | X | X | X | memory usage in bytes |
| | [0].mem_limit | X | X | X | X | X | memory limit (max mem) in bytes |
| | [0].mem_percent | X | X | X | X | X | memory usage in percent |
| | [0].cpu_percent | X | X | X | X | X | cpu usage in percent |
| | [0].pids | X | X | X | X | X | number of processes |
| | [0].netIO.rx | X | X | X | X | X | received bytes via network |
| | [0].netIO.wx | X | X | X | X | X | sent bytes via network |
| | [0].blockIO.r | X | X | X | X | X | bytes read from BlockIO |
| | [0].blockIO.w | X | X | X | X | X | bytes written to BlockIO |
| | [0].cpu_stats | X | X | X | X | X | detailed cpu stats |
| | [0].percpu_stats | X | X | X | X | X | detailed per cpu stats |
| | [0].memory_stats | X | X | X | X | X | detailed memory stats |
| | [0].networks | X | X | X | X | X | detailed network stats per interface |
| si.dockerContainerProcesses(id, cb) | [{...}] | X | X | X | X | X | array of processes inside a container |
| | [0].pid_host | X | X | X | X | X | process ID (host) |
| | [0].ppid | X | X | X | X | X | parent process ID |
| | [0].pgid | X | X | X | X | X | process group ID |
| | [0].user | X | X | X | X | X | effective user name |
| | [0].ruser | X | X | X | X | X | real user name |
| | [0].group | X | X | X | X | X | effective group name |
| | [0].rgroup | X | X | X | X | X | real group name |
| | [0].stat | X | X | X | X | X | process state |
| | [0].time | X | X | X | X | X | accumulated CPU time |
| | [0].elapsed | X | X | X | X | X | elapsed running time |
| | [0].nice | X | X | X | X | X | nice value |
| | [0].rss | X | X | X | X | X | resident set size |
| | [0].vsz | X | X | X | X | X | virtual size in Kbytes |
| | [0].command | X | X | X | X | X | command and arguments |
| si.dockerAll(cb) | {...} | X | X | X | X | X | list of all containers including their stats<br>and processes in one single array |
#### 13. Virtual Box
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.vboxInfo(cb) | [{...}] | X | X | X | X | X | returns array general virtual box info |
| | [0].id | X | X | X | X | X | virtual box ID |
| | [0].name | X | X | X | X | X | name |
| | [0].running | X | X | X | X | X | vbox is running |
| | [0].started | X | X | X | X | X | started date time |
| | [0].runningSince | X | X | X | X | X | running since (secs) |
| | [0].stopped | X | X | X | X | X | stopped date time |
| | [0].stoppedSince | X | X | X | X | X | stopped since (secs) |
| | [0].guestOS | X | X | X | X | X | Guest OS |
| | [0].hardwareUUID | X | X | X | X | X | Hardware UUID |
| | [0].memory | X | X | X | X | X | Memory in MB |
| | [0].vram | X | X | X | X | X | VRAM in MB |
| | [0].cpus | X | X | X | X | X | CPUs |
| | [0].cpuExepCap | X | X | X | X | X | CPU exec cap |
| | [0].cpuProfile | X | X | X | X | X | CPU profile |
| | [0].chipset | X | X | X | X | X | chipset |
| | [0].firmware | X | X | X | X | X | firmware |
| | [0].pageFusion | X | X | X | X | X | page fusion |
| | [0].configFile | X | X | X | X | X | config file |
| | [0].snapshotFolder | X | X | X | X | X | snapshot folder |
| | [0].logFolder | X | X | X | X | X | log folder path |
| | [0].HPET | X | X | X | X | X | HPET |
| | [0].PAE | X | X | X | X | X | PAE |
| | [0].longMode | X | X | X | X | X | long mode |
| | [0].tripleFaultReset | X | X | X | X | X | triple fault reset |
| | [0].APIC | X | X | X | X | X | APIC |
| | [0].X2APIC | X | X | X | X | X | X2APIC |
| | [0].ACPI | X | X | X | X | X | ACPI |
| | [0].IOAPIC | X | X | X | X | X | IOAPIC |
| | [0].biosAPICmode | X | X | X | X | X | BIOS APIC mode |
| | [0].bootMenuMode | X | X | X | X | X | boot menu Mode |
| | [0].bootDevice1 | X | X | X | X | X | bootDevice1 |
| | [0].bootDevice2 | X | X | X | X | X | bootDevice2 |
| | [0].bootDevice3 | X | X | X | X | X | bootDevice3 |
| | [0].bootDevice4 | X | X | X | X | X | bootDevice4 |
| | [0].timeOffset | X | X | X | X | X | time Offset |
| | [0].RTC | X | X | X | X | X | RTC |
#### 14. "Get All at once" - functions
| Function | Result object | Linux | BSD | Mac | Win | Sun | Comments |
| --------------- | ------------- | ----- | ------- | --- | --- | --- | -------- |
| si.getStaticData(cb) | {...} | X | X | X | X | X | all static data at once |
| si.getDynamicData(srv,iface,cb) | {...} | X | X | X | X | X | all dynamic data at once<br>Specify services and interfaces to monitor<br>Defaults to first external network interface<br>Pass "*" for ALL services (linux/win only)<br>Pass "*" for ALL network interfaces |
| si.getAllData(srv,iface,cb) | {...} | X | X | X | X | X | all data at once<br>Specify services and interfaces to monitor<br>Defaults to first external network interface<br>Pass "*" for ALL services (linux/win only)<br>Pass "*" for ALL network interfaces |
### cb: Asynchronous Function Calls (callback)
Remember: all functions (except `version` and `time`) are implemented as asynchronous functions! There are now three ways to consume them:
**Callback Style**
```js
const si = require('systeminformation');
si.cpu(function(data) {
console.log('CPU Information:');
console.log('- manufucturer: ' + data.manufacturer);
console.log('- brand: ' + data.brand);
console.log('- speed: ' + data.speed);
console.log('- cores: ' + data.cores);
console.log('- physical cores: ' + data.physicalCores);
console.log('...');
})
```
### Promises
**Promises Style** is new in version 3.0.
When omitting callback parameter (cb), then you can use all function in a promise oriented way. All functions (exept of `version` and `time`) are returning a promise, that you can consume:
```js
const si = require('systeminformation');
si.cpu()
.then(data => {
console.log('CPU Information:');
console.log('- manufucturer: ' + data.manufacturer);
console.log('- brand: ' + data.brand);
console.log('- speed: ' + data.speed);
console.log('- cores: ' + data.cores);
console.log('- physical cores: ' + data.physicalCores);
console.log('...');
})
.catch(error => console.error(error));
```
### Async / Await
**Using async / await** (available since node v7.6)
Since node v7.6 you can also use the `async` / `await` pattern. The above example would then look like this:
```js
const si = require('systeminformation');
async function cpuData() {
try {
const data = await si.cpu();
console.log('CPU Information:');
console.log('- manufucturer: ' + data.manufacturer);
console.log('- brand: ' + data.brand);
console.log('- speed: ' + data.speed);
console.log('- cores: ' + data.cores);
console.log('- physical cores: ' + data.physicalCores);
console.log('...');
} catch (e) {
console.log(e)
}
}
```
## Known Issues
#### macOS - Temperature Sensor
To be able to measure temperature on macOS I created a little additional package. Due to some difficulties
in NPM with `optionalDependencies` I unfortunately was getting unexpected warnings on other platforms.
So I decided to drop this optional dependency for macOS - so by default, you will not get correct values.
But if you need to detect macOS temperature just run the following additional
installation command:
```bash
$ npm install osx-temperature-sensor --save
```
`systeminformation` will then detect this additional library and return the temperature when calling systeminformations standard function `cpuTemperature()`
#### Windows Temperature, Battery, ...
`wmic` - which is used to determine temperature and battery sometimes needs to be run with admin
privileges. So if you do not get any values, try to run it again with according
privileges. If you still do not get any values, your system might not support this feature.
In some cases we also discovered that `wmic` returned incorrect temperature values.
#### Linux Temperature
In some cases you need to install the linux `sensors` package to be able to measure temperature
e.g. on DEBIAN based systems by running `sudo apt-get install lm-sensors`
#### Linux S.M.A.R.T. Status
To be able to detect S.M.A.R.T. status on Linux you need to install `smartmontools`. On DEBIAN based linux distributions you can install it by running `sudo apt-get install smartmontools`
## *: Additional Notes
In `fsStats()`, `disksIO()` and `networkStats()` the results / sec. values (rx_sec, IOPS, ...) are calculated correctly beginning
with the second call of the function. It is determined by calculating the difference of transferred bytes / IOs
divided by the time between two calls of the function.
The first time you are calling one of this functions, you will get `-1` for transfer rates. The second time, you should then get statistics based on the time between the two calls ...
So basically, if you e.g. need a values for network stats every second, your code should look like this:
```js
const si = require('systeminformation');
setInterval(function() {
si.networkStats().then(data => {
console.log(data);
})
}, 1000)
```
Beginning with the second call, you get network transfer values per second.
## Finding new issues
I am happy to discuss any comments and suggestions. Please feel free to contact me if you see any possibility of improvement!
## Comments
If you have ideas or comments, please do not hesitate to contact me.
Happy monitoring!
Sincerely,
Sebastian Hildebrandt, [+innovations](http://www.plus-innovations.com)
## Credits
Written by Sebastian Hildebrandt [sebhildebrandt](https://github.com/sebhildebrandt)
#### Contributers
- Guillaume Legrain [glegrain](https://github.com/glegrain)
- Riccardo Novaglia [richy24](https://github.com/richy24)
- Quentin Busuttil [Buzut](https://github.com/Buzut)
- lapsio [lapsio](https://github.com/lapsio)
- csy [csy](https://github.com/csy1983)
- Tiago Roldão [tiagoroldao](https://github.com/tiagoroldao)
- dragonjet [dragonjet](https://github.com/dragonjet)
- Adam Reis [adamreisnz](https://github.com/adamreisnz)
- Jimi M [ItsJimi](https://github.com/ItsJimi)
- Git² [GitSquared](https://github.com/GitSquared)
- weiyin [weiyin](https://github.com/weiyin)
- Jorai Rijsdijk [Erackron](https://github.com/Erackron)
- Rasmus Porsager [porsager](https://github.com/porsager)
- Nathan Patten [nrpatten](https://github.com/nrpatten)
OSX Temperature: credits here are going to:
- Massimiliano Marcon [mmarcon](https://github.com/mmarcon) for his work on [smc-code][smc-code-url]
- Sébastien Lavoie [lavoiesl](https://github.com/lavoiesl) for his work on [osx-cpu-temp][osx-cpu-temp-url] code.
## Copyright Information
Linux is a registered trademark of Linus Torvalds. Apple, macOS, OS X are registered trademarks of Apple Inc.,
Windows is a registered trademark of Microsoft Corporation. Node.js is a trademark of Joyent Inc.,
Intel is a trademark of Intel Corporation, AMD is a trademark of Advanced Micro Devices Inc.,
Raspberry Pi is a trademark of the Raspberry Pi Foundation, Debian is a trademark of the Debian Project,
Ubuntu is a trademark of Canonical Ltd., FreeBSD is a registered trademark of The FreeBSD Foundation,
NetBSD is a registered trademark of The NetBSD Foundation, Docker is a trademark of Docker, Inc., Sun,
Solaris, OpenSolaris and registered trademarks of Sun Microsystems.
All other trademarks are the property of their respective owners.
## License [![MIT license][license-img]][license-url]
>The [`MIT`][license-url] License (MIT)
>
>Copyright &copy; 2014-2019 Sebastian Hildebrandt, [+innovations](http://www.plus-innovations.com).
>
>Permission is hereby granted, free of charge, to any person obtaining a copy
>of this software and associated documentation files (the "Software"), to deal
>in the Software without restriction, including without limitation the rights
>to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>copies of the Software, and to permit persons to whom the Software is
>furnished to do so, subject to the following conditions:
>
>The above copyright notice and this permission notice shall be included in
>all copies or substantial portions of the Software.
>
>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
>AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>THE SOFTWARE.
>
>Further details see [LICENSE](LICENSE) file.
[npm-image]: https://img.shields.io/npm/v/systeminformation.svg?style=flat-square
[npm-url]: https://npmjs.org/package/systeminformation
[downloads-image]: https://img.shields.io/npm/dm/systeminformation.svg?style=flat-square
[downloads-url]: https://npmjs.org/package/systeminformation
[lgtm-badge]: https://img.shields.io/lgtm/grade/javascript/g/sebhildebrandt/systeminformation.svg?style=flat-square
[lgtm-badge-url]: https://lgtm.com/projects/g/sebhildebrandt/systeminformation/context:javascript
[lgtm-alerts]: https://img.shields.io/lgtm/alerts/g/sebhildebrandt/systeminformation.svg?style=flat-square
[lgtm-alerts-url]: https://lgtm.com/projects/g/sebhildebrandt/systeminformation/alerts
[license-url]: https://github.com/sebhildebrandt/systeminformation/blob/master/LICENSE
[license-img]: https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square
[npmjs-license]: https://img.shields.io/npm/l/systeminformation.svg?style=flat-square
[changelog-url]: https://github.com/sebhildebrandt/systeminformation/blob/master/CHANGELOG.md
[caretaker-url]: https://github.com/sebhildebrandt
[caretaker-image]: https://img.shields.io/badge/caretaker-sebhildebrandt-blue.svg?style=flat-square
[nodejs-url]: https://nodejs.org/en/
[docker-url]: https://www.docker.com/
[systeminformation-url]: https://systeminformation.io
[daviddm-img]: https://img.shields.io/david/sebhildebrandt/systeminformation.svg?style=flat-square
[daviddm-url]: https://david-dm.org/sebhildebrandt/systeminformation
[issues-img]: https://img.shields.io/github/issues/sebhildebrandt/systeminformation.svg?style=flat-square
[issues-url]: https://github.com/sebhildebrandt/systeminformation/issues
[closed-issues-img]: https://img.shields.io/github/issues-closed-raw/sebhildebrandt/systeminformation.svg?style=flat-square
[closed-issues-url]: https://github.com/sebhildebrandt/systeminformation/issues?q=is%3Aissue+is%3Aclosed
[mmon-npm-url]: https://npmjs.org/package/mmon
[mmon-github-url]: https://github.com/sebhildebrandt/mmon
[smc-code-url]: https://github.com/mmarcon/node-smc
[osx-cpu-temp-url]: https://github.com/lavoiesl/osx-cpu-temp
'use strict';
// @ts-check;
// ==================================================================================
// battery.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 6. Battery
// ----------------------------------------------------------------------------------
const exec = require('child_process').exec;
const fs = require('fs');
const util = require('./util');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
module.exports = function (callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
hasbattery: false,
cyclecount: 0,
ischarging: false,
maxcapacity: 0,
currentcapacity: 0,
percent: 0,
timeremaining: -1,
acconnected: true,
type: '',
model: '',
manufacturer: '',
serial: ''
};
if (_linux) {
let battery_path = '';
if (fs.existsSync('/sys/class/power_supply/BAT1/uevent')) {
battery_path = '/sys/class/power_supply/BAT1/';
} else if (fs.existsSync('/sys/class/power_supply/BAT0/uevent')) {
battery_path = '/sys/class/power_supply/BAT0/';
}
if (battery_path) {
exec('cat ' + battery_path + 'uevent', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result.ischarging = (util.getValue(lines, 'POWER_SUPPLY_STATUS', '=').toLowerCase() === 'charging');
result.acconnected = result.ischarging;
result.cyclecount = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CYCLE_COUNT', '='), 10);
result.maxcapacity = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CHARGE_FULL', '='), 10);
if (!result.maxcapacity) {
result.maxcapacity = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_ENERGY_FULL', '='), 10);
}
result.currentcapacity = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CHARGE_NOW', '='), 10);
if (!result.currentcapacity) {
result.currentcapacity = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_ENERGY_NOW', '='), 10);
}
const percent = util.getValue(lines, 'POWER_SUPPLY_CAPACITY', '=');
const energy = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_ENERGY_NOW', '='), 10);
const power = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_POWER_NOW', '='), 10);
const current = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CURRENT_NOW', '='), 10);
result.percent = parseInt('0' + percent, 10);
if (result.maxcapacity && result.currentcapacity) {
result.hasbattery = true;
if (!percent) {
result.percent = 100.0 * result.currentcapacity / result.maxcapacity;
}
}
if (result.ischarging) {
result.hasbattery = true;
}
if (energy && power) {
result.timeremaining = Math.floor(energy / power * 60);
} else if (current && result.currentcapacity) {
result.timeremaining = Math.floor(result.currentcapacity / current * 60);
}
result.type = util.getValue(lines, 'POWER_SUPPLY_TECHNOLOGY', '=');
result.model = util.getValue(lines, 'POWER_SUPPLY_MODEL_NAME', '=');
result.manufacturer = util.getValue(lines, 'POWER_SUPPLY_MANUFACTURER', '=');
result.serial = util.getValue(lines, 'POWER_SUPPLY_SERIAL_NUMBER', '=');
if (callback) { callback(result); }
resolve(result);
}
});
} else {
if (callback) { callback(result); }
resolve(result);
}
}
if (_freebsd || _openbsd || _netbsd) {
exec('sysctl hw.acpi.battery hw.acpi.acline', function (error, stdout) {
let lines = stdout.toString().split('\n');
const batteries = parseInt('0' + util.getValue(lines, 'hw.acpi.battery.units'), 10);
const percent = parseInt('0' + util.getValue(lines, 'hw.acpi.battery.life'), 10);
result.hasbattery = (batteries > 0);
result.cyclecount = -1;
result.ischarging = util.getValue(lines, 'hw.acpi.acline') !== '1';
result.acconnected = result.ischarging;
result.maxcapacity = -1;
result.currentcapacity = -1;
result.percent = batteries ? percent : -1;
if (callback) { callback(result); }
resolve(result);
});
}
if (_darwin) {
exec('ioreg -n AppleSmartBattery -r | egrep "CycleCount|IsCharging|MaxCapacity|CurrentCapacity|BatterySerialNumber|TimeRemaining"; pmset -g batt | grep %', function (error, stdout) {
if (stdout) {
let lines = stdout.toString().replace(/ +/g, '').replace(/"+/g, '').replace(/-/g, '').split('\n');
result.cyclecount = parseInt('0' + util.getValue(lines, 'cyclecount', '='), 10);
result.maxcapacity = parseInt('0' + util.getValue(lines, 'maxcapacity', '='), 10);
result.currentcapacity = parseInt('0' + util.getValue(lines, 'currentcapacity', '='), 10);
result.manufacturer = 'Apple';
result.serial = util.getValue(lines, 'BatterySerialNumber', '=');
let percent = -1;
const line = util.getValue(lines, 'internal', 'Battery');
let parts = line.split(';');
if (parts && parts[0]) {
let parts2 = parts[0].split('\t');
if (parts2 && parts2[1]) {
percent = parseFloat(parts2[1].trim().replace(/%/g, ''));
}
}
if (parts && parts[1]) {
result.ischarging = (parts[1].trim() === 'charging');
result.acconnected = (parts[1].trim() !== 'discharging');
} else {
result.ischarging = util.getValue(lines, 'ischarging', '=').toLowerCase() === 'yes';
result.acconnected = result.ischarging;
}
if (result.maxcapacity && result.currentcapacity) {
result.hasbattery = true;
result.type = 'Li-ion';
result.percent = percent !== -1 ? percent : Math.round(100.0 * result.currentcapacity / result.maxcapacity);
if (!result.ischarging) {
result.timeremaining = parseInt('0' + util.getValue(lines, 'TimeRemaining', '='), 10);
}
}
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_sunos) {
if (callback) { callback(result); }
resolve(result);
}
if (_windows) {
try {
util.wmic('Path Win32_Battery Get BatteryStatus, DesignCapacity, EstimatedChargeRemaining /value').then((stdout) => {
if (stdout) {
let lines = stdout.split('\r\n');
let status = util.getValue(lines, 'BatteryStatus', '=').trim();
// 1 = "Discharging"
// 2 = "On A/C"
// 3 = "Fully Charged"
// 4 = "Low"
// 5 = "Critical"
// 6 = "Charging"
// 7 = "Charging High"
// 8 = "Charging Low"
// 9 = "Charging Critical"
// 10 = "Undefined"
// 11 = "Partially Charged"
if (status && status != '10') {
const statusValue = parseInt(status);
result.hasbattery = true;
result.maxcapacity = parseInt(util.getValue(lines, 'DesignCapacity', '=') || 0);
result.percent = parseInt(util.getValue(lines, 'EstimatedChargeRemaining', '=') || 0);
result.currentcapacity = parseInt(result.maxcapacity * result.percent / 100);
result.ischarging = (statusValue >= 6 && statusValue <= 9) || statusValue === 11 || (!(statusValue === 3) && !(statusValue === 1) && result.percent < 100);
result.acconnected = result.ischarging || statusValue === 2;
}
}
if (callback) { callback(result); }
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
};
'use strict';
// @ts-check
// ==================================================================================
// cpu.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 4. CPU
// ----------------------------------------------------------------------------------
const os = require('os');
const exec = require('child_process').exec;
const fs = require('fs');
const util = require('./util');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
let _cpu_speed = '0.00';
let _current_cpu = {
user: 0,
nice: 0,
system: 0,
idle: 0,
irq: 0,
load: 0,
tick: 0,
ms: 0,
currentload: 0,
currentload_user: 0,
currentload_system: 0,
currentload_nice: 0,
currentload_idle: 0,
currentload_irq: 0,
raw_currentload: 0,
raw_currentload_user: 0,
raw_currentload_system: 0,
raw_currentload_nice: 0,
raw_currentload_idle: 0,
raw_currentload_irq: 0
};
let _cpus = [];
let _corecount = 0;
const AMDBaseFrequencies = {
'FX|4100': '3.6',
'FX|4120': '3.9',
'FX|4130': '3.8',
'FX|4150': '3.8',
'FX|4170': '4.2',
'FX|6100': '3.3',
'FX|6120': '3.6',
'FX|6130': '3.6',
'FX|6200': '3.8',
'FX|8100': '2.8',
'FX|8120': '3.1',
'FX|8140': '3.2',
'FX|8150': '3.6',
'FX|8170': '3.9',
'FX|4300': '3.8',
'FX|4320': '4.0',
'FX|4350': '4.2',
'FX|6300': '3.5',
'FX|6350': '3.9',
'FX|8300': '3.3',
'FX|8310': '3.4',
'FX|8320': '3.5',
'FX|8350': '4.0',
'FX|8370': '4.0',
'FX|9370': '4.4',
'FX|9590': '4.7',
'FX|8320E': '3.2',
'FX|8370E': '3.3',
'1950X': '3.4',
'1920X': '3.5',
'1920': '3.2',
'1900X': '3.8',
'1800X': '3.6',
'1700X': '3.4',
'Pro 1700X': '3.5',
'1700': '3.0',
'Pro 1700': '3.0',
'1600X': '3.6',
'1600': '3.2',
'Pro 1600': '3.2',
'1500X': '3.5',
'Pro 1500': '3.5',
'1400': '3.2',
'1300X': '3.5',
'Pro 1300': '3.5',
'1200': '3.1',
'Pro 1200': '3.1',
'2200U': '2.5',
'2300U': '2.0',
'Pro 2300U': '2.0',
'2500U': '2.0',
'Pro 2500U': '2.2',
'2700U': '2.0',
'Pro 2700U': '2.2',
'2600H': '3.2',
'2800H': '3.3',
'7601': '2.2',
'7551': '2.0',
'7501': '2.0',
'74501': '2.3',
'7401': '2.0',
'7351': '2.4',
'7301': '2.2',
'7281': '2.1',
'7251': '2.1',
'7551P': '2.0',
'7401P': '2.0',
'7351P': '2.4'
};
const socketTypes = {
1: 'Other',
2: 'Unknown',
3: 'Daughter Board',
4: 'ZIF Socket',
5: 'Replacement/Piggy Back',
6: 'None',
7: 'LIF Socket',
8: 'Slot 1',
9: 'Slot 2',
10: '370 Pin Socket',
11: 'Slot A',
12: 'Slot M',
13: '423',
14: 'A (Socket 462)',
15: '478',
16: '754',
17: '940',
18: '939',
19: 'mPGA604',
20: 'LGA771',
21: 'LGA775',
22: 'S1',
23: 'AM2',
24: 'F (1207)',
25: 'LGA1366',
26: 'G34',
27: 'AM3',
28: 'C32',
29: 'LGA1156',
30: 'LGA1567',
31: 'PGA988A',
32: 'BGA1288',
33: 'rPGA988B',
34: 'BGA1023',
35: 'BGA1224',
36: 'LGA1155',
37: 'LGA1356',
38: 'LGA2011',
39: 'FS1',
40: 'FS2',
41: 'FM1',
42: 'FM2',
43: 'LGA2011-3',
44: 'LGA1356-3',
45: 'LGA1150',
46: 'BGA1168',
47: 'BGA1234',
48: 'BGA1364',
49: 'AM4',
50: 'LGA1151',
51: 'BGA1356',
52: 'BGA1440',
53: 'BGA1515',
54: 'LGA3647-1',
55: 'SP3',
56: 'SP3r2',
57: 'LGA2066',
58: 'BGA1392',
59: 'BGA1510',
60: 'BGA1528'
};
function cpuBrandManufacturer(res) {
res.brand = res.brand.replace(/\(R\)+/g, '®').replace(/\s+/g, ' ').trim();
res.brand = res.brand.replace(/\(TM\)+/g, '').replace(/\s+/g, ' ').trim();
res.brand = res.brand.replace(/\(C\)+/g, '©').replace(/\s+/g, ' ').trim();
res.brand = res.brand.replace(/CPU+/g, '').replace(/\s+/g, ' ').trim();
res.manufacturer = res.brand.split(' ')[0];
let parts = res.brand.split(' ');
parts.shift();
res.brand = parts.join(' ');
return res;
}
function getAMDSpeed(brand) {
let result = '0.00';
for (let key in AMDBaseFrequencies) {
if (AMDBaseFrequencies.hasOwnProperty(key)) {
let parts = key.split('|');
let found = 0;
parts.forEach(item => {
if (brand.indexOf(item) > -1) {
found++;
}
});
if (found === parts.length) {
result = AMDBaseFrequencies[key];
}
}
}
return result;
}
// --------------------------
// CPU - brand, speed
function getCpu() {
return new Promise((resolve) => {
process.nextTick(() => {
const UNKNOWN = 'unknown';
let result = {
manufacturer: UNKNOWN,
brand: UNKNOWN,
vendor: '',
family: '',
model: '',
stepping: '',
revision: '',
voltage: '',
speed: '0.00',
speedmin: '',
speedmax: '',
cores: util.cores(),
physicalCores: util.cores(),
processors: 1,
socket: '',
cache: {}
};
if (_darwin) {
exec('sysctl machdep.cpu hw.cpufrequency_max hw.cpufrequency_min hw.packages hw.physicalcpu_max hw.ncpu', function (error, stdout) {
// if (!error) {
let lines = stdout.toString().split('\n');
const modelline = util.getValue(lines, 'machdep.cpu.brand_string');
result.brand = modelline.split('@')[0].trim();
result.speed = modelline.split('@')[1].trim();
result.speed = parseFloat(result.speed.replace(/GHz+/g, '')).toFixed(2);
_cpu_speed = result.speed;
result = cpuBrandManufacturer(result);
result.speedmin = (util.getValue(lines, 'hw.cpufrequency_min') / 1000000000.0).toFixed(2);
result.speedmax = (util.getValue(lines, 'hw.cpufrequency_max') / 1000000000.0).toFixed(2);
result.vendor = util.getValue(lines, 'machdep.cpu.vendor');
result.family = util.getValue(lines, 'machdep.cpu.family');
result.model = util.getValue(lines, 'machdep.cpu.model');
result.stepping = util.getValue(lines, 'machdep.cpu.stepping');
const countProcessors = util.getValue(lines, 'hw.packages');
const countCores = util.getValue(lines, 'hw.physicalcpu_max');
const countThreads = util.getValue(lines, 'hw.ncpu');
if (countProcessors) {
result.processors = parseInt(countProcessors) || 1;
}
if (countCores && countThreads) {
result.cores = parseInt(countThreads) || util.cores();
result.physicalCores = parseInt(countCores) || util.cores();
}
// }
cpuCache().then(res => {
result.cache = res;
resolve(result);
});
});
}
if (_linux) {
let modelline = '';
let lines = [];
if (os.cpus()[0] && os.cpus()[0].model) modelline = os.cpus()[0].model;
exec('export LC_ALL=C; lscpu; unset LC_ALL', function (error, stdout) {
if (!error) {
lines = stdout.toString().split('\n');
}
modelline = util.getValue(lines, 'model name') || modelline;
result.brand = modelline.split('@')[0].trim();
result.speed = modelline.split('@')[1] ? parseFloat(modelline.split('@')[1].trim()).toFixed(2) : '0.00';
if (result.speed === '0.00' && result.brand.indexOf('AMD') > -1) {
result.speed = getAMDSpeed(result.brand);
}
if (result.speed === '0.00') {
let current = getCpuCurrentSpeedSync();
if (current.avg !== 0) result.speed = current.avg.toFixed(2);
}
_cpu_speed = result.speed;
result.speedmin = Math.round(parseFloat(util.getValue(lines, 'cpu min mhz').replace(/,/g, '.')) / 10.0) / 100;
result.speedmin = result.speedmin ? parseFloat(result.speedmin).toFixed(2) : '';
result.speedmax = Math.round(parseFloat(util.getValue(lines, 'cpu max mhz').replace(/,/g, '.')) / 10.0) / 100;
result.speedmax = result.speedmax ? parseFloat(result.speedmax).toFixed(2) : '';
result = cpuBrandManufacturer(result);
result.vendor = util.getValue(lines, 'vendor id');
// if (!result.vendor) { result.vendor = util.getValue(lines, 'anbieterkennung'); }
result.family = util.getValue(lines, 'cpu family');
// if (!result.family) { result.family = util.getValue(lines, 'prozessorfamilie'); }
result.model = util.getValue(lines, 'model:');
// if (!result.model) { result.model = util.getValue(lines, 'modell:'); }
result.stepping = util.getValue(lines, 'stepping');
result.revision = util.getValue(lines, 'cpu revision');
result.cache.l1d = util.getValue(lines, 'l1d cache');
if (result.cache.l1d) { result.cache.l1d = parseInt(result.cache.l1d) * (result.cache.l1d.indexOf('K') !== -1 ? 1024 : 1); }
result.cache.l1i = util.getValue(lines, 'l1i cache');
if (result.cache.l1i) { result.cache.l1i = parseInt(result.cache.l1i) * (result.cache.l1i.indexOf('K') !== -1 ? 1024 : 1); }
result.cache.l2 = util.getValue(lines, 'l2 cache');
if (result.cache.l2) { result.cache.l2 = parseInt(result.cache.l2) * (result.cache.l2.indexOf('K') !== -1 ? 1024 : 1); }
result.cache.l3 = util.getValue(lines, 'l3 cache');
if (result.cache.l3) { result.cache.l3 = parseInt(result.cache.l3) * (result.cache.l3.indexOf('K') !== -1 ? 1024 : 1); }
// socket type
lines = [];
exec('export LC_ALL=C; dmidecode –t 4 2>/dev/null | grep "Upgrade: Socket"; unset LC_ALL', function (error2, stdout2) {
lines = stdout2.toString().split('\n');
if (lines && lines.length) {
result.socket = util.getValue(lines, 'Upgrade').replace('Socket', '').trim();
}
// # processurs & # threads/core - method 1
let threadsPerCoreInt = 0;
lines = [];
exec('cat /proc/cpuinfo | grep -E "physical id|core id"', function (error2, stdout3) {
lines = stdout3.toString().split('\n');
if (lines && lines.length) {
result.processors = util.countUniqueLines(lines, 'physical id') || 1;
result.physicalCores = util.countUniqueLines(lines, 'core id') / result.processors;
if (result.physicalCores) {
threadsPerCoreInt = result.cores / result.physicalCores;
}
}
// # threads/core - method 2
if (threadsPerCoreInt === 0) {
const threadsPerCore = util.getValue(lines, 'thread(s) per core');
if (threadsPerCore) {
threadsPerCoreInt = parseInt(threadsPerCore, 10);
if (!isNaN(threadsPerCoreInt)) {
result.physicalCores = result.cores / threadsPerCoreInt;
}
}
}
resolve(result);
});
});
});
}
if (_freebsd || _openbsd || _netbsd) {
let modelline = '';
let lines = [];
if (os.cpus()[0] && os.cpus()[0].model) modelline = os.cpus()[0].model;
exec('export LC_ALL=C; dmidecode -t 4 2>/dev/null; dmidecode -t 7 2>/dev/null; unset LC_ALL', function (error, stdout) {
let cache = [];
if (!error) {
const data = stdout.toString().split('# dmidecode');
const processor = data.length > 0 ? data[1] : '';
cache = data.length > 1 ? data[2].split('Cache Information') : [];
lines = processor.split('\n');
}
result.brand = modelline.split('@')[0].trim();
result.speed = modelline.split('@')[1] ? parseFloat(modelline.split('@')[1].trim()).toFixed(2) : '0.00';
if (result.speed === '0.00' && result.brand.indexOf('AMD') > -1) {
result.speed = getAMDSpeed(result.brand);
}
if (result.speed === '0.00') {
let current = getCpuCurrentSpeedSync();
if (current.avg !== 0) result.speed = current.avg.toFixed(2);
}
_cpu_speed = result.speed;
result.speedmin = '';
result.speedmax = Math.round(parseFloat(util.getValue(lines, 'max speed').replace(/Mhz/g, '')) / 10.0) / 100;
result.speedmax = result.speedmax ? parseFloat(result.speedmax).toFixed(2) : '';
result = cpuBrandManufacturer(result);
result.vendor = util.getValue(lines, 'manufacturer');
let sig = util.getValue(lines, 'signature');
sig = sig.split(',');
for (var i = 0; i < sig.length; i++) {
sig[i] = sig[i].trim();
}
result.family = util.getValue(sig, 'Family', ' ', true);
result.model = util.getValue(sig, 'Model', ' ', true);
result.stepping = util.getValue(sig, 'Stepping', ' ', true);
result.revision = '';
const voltage = parseFloat(util.getValue(lines, 'voltage'));
result.voltage = isNaN(voltage) ? '' : voltage.toFixed(2);
for (let i = 0; i < cache.length; i++) {
lines = cache[i].split('\n');
let cacheType = util.getValue(lines, 'Socket Designation').toLowerCase().replace(' ', '-').split('-');
cacheType = cacheType.length ? cacheType[0] : '';
const sizeParts = util.getValue(lines, 'Installed Size').split(' ');
let size = parseInt(sizeParts[0], 10);
const unit = sizeParts.length > 1 ? sizeParts[1] : 'kb';
size = size * (unit === 'kb' ? 1024 : (unit === 'mb' ? 1024 * 1024 : (unit === 'gb' ? 1024 * 1024 * 1024 : 1)));
if (cacheType) {
if (cacheType === 'l1') {
result.cache[cacheType + 'd'] = size / 2;
result.cache[cacheType + 'i'] = size / 2;
} else {
result.cache[cacheType] = size;
}
}
}
// socket type
result.socket = util.getValue(lines, 'Upgrade').replace('Socket', '').trim();
// # threads / # cores
const threadCount = util.getValue(lines, 'thread count').trim();
const coreCount = util.getValue(lines, 'core count').trim();
if (coreCount && threadCount) {
result.cores = threadCount;
result.physicalCores = coreCount;
}
resolve(result);
});
}
if (_sunos) {
resolve(result);
}
if (_windows) {
try {
util.wmic('cpu get /value').then((stdout, error) => {
if (!error) {
let lines = stdout.split('\r\n');
let name = util.getValue(lines, 'name', '=') || '';
if (name.indexOf('@') >= 0) {
result.brand = name.split('@')[0].trim();
result.speed = name.split('@')[1].trim();
result.speed = parseFloat(result.speed.replace(/GHz+/g, '').trim()).toFixed(2);
_cpu_speed = result.speed;
} else {
result.brand = name.trim();
result.speed = 0;
}
result = cpuBrandManufacturer(result);
result.revision = util.getValue(lines, 'revision', '=');
result.cache.l1d = 0;
result.cache.l1i = 0;
result.cache.l2 = util.getValue(lines, 'l2cachesize', '=');
result.cache.l3 = util.getValue(lines, 'l3cachesize', '=');
if (result.cache.l2) { result.cache.l2 = parseInt(result.cache.l2, 10) * 1024; }
if (result.cache.l3) { result.cache.l3 = parseInt(result.cache.l3, 10) * 1024; }
result.vendor = util.getValue(lines, 'manufacturer', '=');
result.speedmax = Math.round(parseFloat(util.getValue(lines, 'maxclockspeed', '=').replace(/,/g, '.')) / 10.0) / 100;
result.speedmax = result.speedmax ? parseFloat(result.speedmax).toFixed(2) : '';
if (!result.speed && result.brand.indexOf('AMD') > -1) {
result.speed = getAMDSpeed(result.brand);
}
if (!result.speed) {
result.speed = result.speedmax;
}
let description = util.getValue(lines, 'description', '=').split(' ');
for (let i = 0; i < description.length; i++) {
if (description[i].toLowerCase().startsWith('family') && (i + 1) < description.length && description[i + 1]) {
result.family = description[i + 1];
}
if (description[i].toLowerCase().startsWith('model') && (i + 1) < description.length && description[i + 1]) {
result.model = description[i + 1];
}
if (description[i].toLowerCase().startsWith('stepping') && (i + 1) < description.length && description[i + 1]) {
result.stepping = description[i + 1];
}
}
// socket type
const socketId = util.getValue(lines, 'UpgradeMethod', '=');
if (socketTypes[socketId]) {
result.socket = socketTypes[socketId];
}
// # threads / # cores
const countProcessors = util.countUniqueLines(lines, 'Caption');
const countThreads = util.getValue(lines, 'NumberOfLogicalProcessors', '=');
const countCores = util.getValue(lines, 'NumberOfCores', '=');
if (countProcessors) {
result.processors = parseInt(countProcessors) || 1;
}
if (countCores && countThreads) {
result.cores = parseInt(countThreads) || util.cores();
result.physicalCores = parseInt(countCores) || util.cores();
}
}
util.wmic('path Win32_CacheMemory get CacheType,InstalledSize,Purpose').then((stdout, error) => {
if (!error) {
let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0);
lines.forEach(function (line) {
if (line !== '') {
line = line.trim().split(/\s\s+/);
// L1 Instructions
if (line[2] === 'L1 Cache' && line[0] === '3') {
result.cache.l1i = parseInt(line[1], 10);
}
// L1 Data
if (line[2] === 'L1 Cache' && line[0] === '4') {
result.cache.l1d = parseInt(line[1], 10);
}
}
});
}
resolve(result);
});
});
} catch (e) {
resolve(result);
}
}
});
});
}
// --------------------------
// CPU - Processor Data
function cpu(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
getCpu().then(result => {
if (callback) { callback(result); }
resolve(result);
});
});
});
}
exports.cpu = cpu;
// --------------------------
// CPU - current speed - in GHz
function getCpuCurrentSpeedSync() {
let cpus = os.cpus();
let minFreq = 999999999;
let maxFreq = 0;
let avgFreq = 0;
let cores = [];
if (cpus.length) {
for (let i in cpus) {
if (cpus.hasOwnProperty(i)) {
avgFreq = avgFreq + cpus[i].speed;
if (cpus[i].speed > maxFreq) maxFreq = cpus[i].speed;
if (cpus[i].speed < minFreq) minFreq = cpus[i].speed;
}
cores.push(parseFloat(((cpus[i].speed + 1) / 1000).toFixed(2)));
}
avgFreq = avgFreq / cpus.length;
return {
min: parseFloat(((minFreq + 1) / 1000).toFixed(2)),
max: parseFloat(((maxFreq + 1) / 1000).toFixed(2)),
avg: parseFloat(((avgFreq + 1) / 1000).toFixed(2)),
cores: cores
};
} else {
return {
min: 0,
max: 0,
avg: 0,
cores: cores
};
}
}
function cpuCurrentspeed(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = getCpuCurrentSpeedSync();
if (result.avg === 0 && _cpu_speed !== '0.00') {
const currCpuSpeed = parseFloat(_cpu_speed);
result = {
min: currCpuSpeed,
max: currCpuSpeed,
avg: currCpuSpeed,
cores: []
};
}
if (callback) { callback(result); }
resolve(result);
});
});
}
exports.cpuCurrentspeed = cpuCurrentspeed;
// --------------------------
// CPU - temperature
// if sensors are installed
function cpuTemperature(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
main: -1.0,
cores: [],
max: -1.0
};
if (_linux) {
exec('sensors', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
let regex = /[+-]([^°]*)/g;
let temps = line.match(regex);
let firstPart = line.split(':')[0].toUpperCase();
if (firstPart.indexOf('PHYSICAL') !== -1 || firstPart.indexOf('PACKAGE') !== -1) {
result.main = parseFloat(temps);
}
if (firstPart.indexOf('CORE ') !== -1) {
result.cores.push(parseFloat(temps));
}
});
if (result.cores.length > 0) {
let maxtmp = Math.max.apply(Math, result.cores);
result.max = (maxtmp > result.main) ? maxtmp : result.main;
}
if (callback) { callback(result); }
resolve(result);
} else {
fs.stat('/sys/class/thermal/thermal_zone0/temp', function (err) {
if (err === null) {
exec('cat /sys/class/thermal/thermal_zone0/temp', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
if (lines.length > 0) {
result.main = parseFloat(lines[0]) / 1000.0;
result.max = result.main;
}
}
if (callback) { callback(result); }
resolve(result);
});
} else {
exec('/opt/vc/bin/vcgencmd measure_temp', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
if (lines.length > 0 && lines[0].indexOf('=')) {
result.main = parseFloat(lines[0].split('=')[1]);
result.max = result.main;
}
}
if (callback) { callback(result); }
resolve(result);
});
}
});
}
});
}
if (_freebsd || _openbsd || _netbsd) {
exec('sysctl dev.cpu | grep temp', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
let sum = 0;
lines.forEach(function (line) {
const parts = line.split(':');
if (parts.length > 0) {
const temp = parseFloat(parts[1].replace(',', '.'));
if (temp > result.max) result.max = temp;
sum = sum + temp;
result.cores.push(temp);
}
});
if (result.cores.length) {
result.main = Math.round(sum / result.cores.length * 100) / 100;
}
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_darwin) {
let osxTemp = null;
try {
osxTemp = require('osx-temperature-sensor');
} catch (er) {
osxTemp = null;
}
if (osxTemp) {
result = osxTemp.cpuTemperature();
}
if (callback) { callback(result); }
resolve(result);
}
if (_sunos) {
if (callback) { callback(result); }
resolve(result);
}
if (_windows) {
try {
util.wmic('/namespace:\\\\root\\wmi PATH MSAcpi_ThermalZoneTemperature get CurrentTemperature').then((stdout, error) => {
if (!error) {
let sum = 0;
let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0);
lines.forEach(function (line) {
let value = (parseInt(line, 10) - 2732) / 10;
sum = sum + value;
if (value > result.max) result.max = value;
result.cores.push(value);
});
if (result.cores.length) {
result.main = sum / result.cores.length;
}
}
if (callback) { callback(result); }
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.cpuTemperature = cpuTemperature;
// --------------------------
// CPU Flags
function cpuFlags(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = '';
if (_windows) {
try {
exec('reg query "HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0" /v FeatureSet', util.execOptsWin, function (error, stdout) {
if (!error) {
let flag_hex = stdout.split('0x').pop().trim();
let flag_bin_unpadded = parseInt(flag_hex, 16).toString(2);
let flag_bin = '0'.repeat(32 - flag_bin_unpadded.length) + flag_bin_unpadded;
// empty flags are the reserved fields in the CPUID feature bit list
// as found on wikipedia:
// https://en.wikipedia.org/wiki/CPUID
let all_flags = [
'fpu', 'vme', 'de', 'pse', 'tsc', 'msr', 'pae', 'mce', 'cx8', 'apic',
'', 'sep', 'mtrr', 'pge', 'mca', 'cmov', 'pat', 'pse-36', 'psn', 'clfsh',
'', 'ds', 'acpi', 'mmx', 'fxsr', 'sse', 'sse2', 'ss', 'htt', 'tm', 'ia64', 'pbe'
];
for (let f = 0; f < all_flags.length; f++) {
if (flag_bin[f] === '1' && all_flags[f] !== '') {
result += ' ' + all_flags[f];
}
}
result = result.trim();
}
if (callback) { callback(result); }
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
if (_linux) {
exec('export LC_ALL=C; lscpu; unset LC_ALL', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
if (line.split(':')[0].toUpperCase().indexOf('FLAGS') !== -1) {
result = line.split(':')[1].trim().toLowerCase();
}
});
}
if (!result) {
exec('cat /proc/cpuinfo', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result = util.getValue(lines, 'features', ':', true).toLowerCase();
}
if (callback) { callback(result); }
resolve(result);
});
} else {
if (callback) { callback(result); }
resolve(result);
}
});
}
if (_freebsd || _openbsd || _netbsd) {
exec('export LC_ALL=C; dmidecode -t 4 2>/dev/null; unset LC_ALL', function (error, stdout) {
let flags = [];
if (!error) {
let parts = stdout.toString().split('\tFlags:');
const lines = parts.length > 1 ? parts[1].split('\tVersion:')[0].split['\n'] : [];
lines.forEach(function (line) {
let flag = (line.indexOf('(') ? line.split('(')[0].toLowerCase() : '').trim().replace(/\t/g, '');
if (flag) {
flags.push(flag);
}
});
}
result = flags.join(' ').trim();
if (callback) { callback(result); }
resolve(result);
});
}
if (_darwin) {
exec('sysctl machdep.cpu.features', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
if (lines.length > 0 && lines[0].indexOf('machdep.cpu.features:') !== -1) {
result = lines[0].split(':')[1].trim().toLowerCase();
}
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_sunos) {
if (callback) { callback(result); }
resolve(result);
}
});
});
}
exports.cpuFlags = cpuFlags;
// --------------------------
// CPU Cache
function cpuCache(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
l1d: -1,
l1i: -1,
l2: -1,
l3: -1,
};
if (_linux) {
exec('export LC_ALL=C; lscpu; unset LC_ALL', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
let parts = line.split(':');
if (parts[0].toUpperCase().indexOf('L1D CACHE') !== -1) {
result.l1d = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
}
if (parts[0].toUpperCase().indexOf('L1I CACHE') !== -1) {
result.l1i = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
}
if (parts[0].toUpperCase().indexOf('L2 CACHE') !== -1) {
result.l2 = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
}
if (parts[0].toUpperCase().indexOf('L3 CACHE') !== -1) {
result.l3 = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
}
});
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_freebsd || _openbsd || _netbsd) {
exec('export LC_ALL=C; dmidecode -t 7 2>/dev/null; unset LC_ALL', function (error, stdout) {
let cache = [];
if (!error) {
const data = stdout.toString();
cache = data.split('Cache Information');
cache.shift();
}
for (let i = 0; i < cache.length; i++) {
const lines = cache[i].split('\n');
let cacheType = util.getValue(lines, 'Socket Designation').toLowerCase().replace(' ', '-').split('-');
cacheType = cacheType.length ? cacheType[0] : '';
const sizeParts = util.getValue(lines, 'Installed Size').split(' ');
let size = parseInt(sizeParts[0], 10);
const unit = sizeParts.length > 1 ? sizeParts[1] : 'kb';
size = size * (unit === 'kb' ? 1024 : (unit === 'mb' ? 1024 * 1024 : (unit === 'gb' ? 1024 * 1024 * 1024 : 1)));
if (cacheType) {
if (cacheType === 'l1') {
result.cache[cacheType + 'd'] = size / 2;
result.cache[cacheType + 'i'] = size / 2;
} else {
result.cache[cacheType] = size;
}
}
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_darwin) {
exec('sysctl hw.l1icachesize hw.l1dcachesize hw.l2cachesize hw.l3cachesize', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
let parts = line.split(':');
if (parts[0].toLowerCase().indexOf('hw.l1icachesize') !== -1) {
result.l1d = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
}
if (parts[0].toLowerCase().indexOf('hw.l1dcachesize') !== -1) {
result.l1i = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
}
if (parts[0].toLowerCase().indexOf('hw.l2cachesize') !== -1) {
result.l2 = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
}
if (parts[0].toLowerCase().indexOf('hw.l3cachesize') !== -1) {
result.l3 = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
}
});
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_sunos) {
if (callback) { callback(result); }
resolve(result);
}
if (_windows) {
try {
util.wmic('cpu get l2cachesize, l3cachesize /value').then((stdout, error) => {
if (!error) {
let lines = stdout.split('\r\n');
result.l1d = 0;
result.l1i = 0;
result.l2 = util.getValue(lines, 'l2cachesize', '=');
result.l3 = util.getValue(lines, 'l3cachesize', '=');
if (result.l2) { result.l2 = parseInt(result.l2, 10) * 1024; }
if (result.l3) { result.l3 = parseInt(result.l3, 10) * 1024; }
}
util.wmic('path Win32_CacheMemory get CacheType,InstalledSize,Purpose').then((stdout, error) => {
if (!error) {
let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0);
lines.forEach(function (line) {
if (line !== '') {
line = line.trim().split(/\s\s+/);
// L1 Instructions
if (line[2] === 'L1 Cache' && line[0] === '3') {
result.l1i = parseInt(line[1], 10);
}
// L1 Data
if (line[2] === 'L1 Cache' && line[0] === '4') {
result.l1d = parseInt(line[1], 10);
}
}
});
}
if (callback) { callback(result); }
resolve(result);
});
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.cpuCache = cpuCache;
// --------------------------
// CPU - current load - in %
function getLoad() {
return new Promise((resolve) => {
process.nextTick(() => {
let loads = os.loadavg().map(function (x) { return x / util.cores(); });
let avgload = parseFloat((Math.max.apply(Math, loads)).toFixed(2));
let result = {};
let now = Date.now() - _current_cpu.ms;
if (now >= 200) {
_current_cpu.ms = Date.now();
const cpus = os.cpus();
let totalUser = 0;
let totalSystem = 0;
let totalNice = 0;
let totalIrq = 0;
let totalIdle = 0;
let cores = [];
_corecount = cpus.length;
for (let i = 0; i < _corecount; i++) {
const cpu = cpus[i].times;
totalUser += cpu.user;
totalSystem += cpu.sys;
totalNice += cpu.nice;
totalIdle += cpu.idle;
totalIrq += cpu.irq;
let tmp_tick = (_cpus && _cpus[i] && _cpus[i].totalTick ? _cpus[i].totalTick : 0);
let tmp_load = (_cpus && _cpus[i] && _cpus[i].totalLoad ? _cpus[i].totalLoad : 0);
let tmp_user = (_cpus && _cpus[i] && _cpus[i].user ? _cpus[i].user : 0);
let tmp_system = (_cpus && _cpus[i] && _cpus[i].sys ? _cpus[i].sys : 0);
let tmp_nice = (_cpus && _cpus[i] && _cpus[i].nice ? _cpus[i].nice : 0);
let tmp_idle = (_cpus && _cpus[i] && _cpus[i].idle ? _cpus[i].idle : 0);
let tmp_irq = (_cpus && _cpus[i] && _cpus[i].irq ? _cpus[i].irq : 0);
_cpus[i] = cpu;
_cpus[i].totalTick = _cpus[i].user + _cpus[i].sys + _cpus[i].nice + _cpus[i].irq + _cpus[i].idle;
_cpus[i].totalLoad = _cpus[i].user + _cpus[i].sys + _cpus[i].nice + _cpus[i].irq;
_cpus[i].currentTick = _cpus[i].totalTick - tmp_tick;
_cpus[i].load = (_cpus[i].totalLoad - tmp_load);
_cpus[i].load_user = (_cpus[i].user - tmp_user);
_cpus[i].load_system = (_cpus[i].sys - tmp_system);
_cpus[i].load_nice = (_cpus[i].nice - tmp_nice);
_cpus[i].load_idle = (_cpus[i].idle - tmp_idle);
_cpus[i].load_irq = (_cpus[i].irq - tmp_irq);
cores[i] = {};
cores[i].load = _cpus[i].load / _cpus[i].currentTick * 100;
cores[i].load_user = _cpus[i].load_user / _cpus[i].currentTick * 100;
cores[i].load_system = _cpus[i].load_system / _cpus[i].currentTick * 100;
cores[i].load_nice = _cpus[i].load_nice / _cpus[i].currentTick * 100;
cores[i].load_idle = _cpus[i].load_idle / _cpus[i].currentTick * 100;
cores[i].load_irq = _cpus[i].load_irq / _cpus[i].currentTick * 100;
cores[i].raw_load = _cpus[i].load;
cores[i].raw_load_user = _cpus[i].load_user;
cores[i].raw_load_system = _cpus[i].load_system;
cores[i].raw_load_nice = _cpus[i].load_nice;
cores[i].raw_load_idle = _cpus[i].load_idle;
cores[i].raw_load_irq = _cpus[i].load_irq;
}
let totalTick = totalUser + totalSystem + totalNice + totalIrq + totalIdle;
let totalLoad = totalUser + totalSystem + totalNice + totalIrq;
let currentTick = totalTick - _current_cpu.tick;
result = {
avgload: avgload,
currentload: (totalLoad - _current_cpu.load) / currentTick * 100,
currentload_user: (totalUser - _current_cpu.user) / currentTick * 100,
currentload_system: (totalSystem - _current_cpu.system) / currentTick * 100,
currentload_nice: (totalNice - _current_cpu.nice) / currentTick * 100,
currentload_idle: (totalIdle - _current_cpu.idle) / currentTick * 100,
currentload_irq: (totalIrq - _current_cpu.irq) / currentTick * 100,
raw_currentload: (totalLoad - _current_cpu.load),
raw_currentload_user: (totalUser - _current_cpu.user),
raw_currentload_system: (totalSystem - _current_cpu.system),
raw_currentload_nice: (totalNice - _current_cpu.nice),
raw_currentload_idle: (totalIdle - _current_cpu.idle),
raw_currentload_irq: (totalIrq - _current_cpu.irq),
cpus: cores
};
_current_cpu = {
user: totalUser,
nice: totalNice,
system: totalSystem,
idle: totalIdle,
irq: totalIrq,
tick: totalTick,
load: totalLoad,
ms: _current_cpu.ms,
currentload: result.currentload,
currentload_user: result.currentload_user,
currentload_system: result.currentload_system,
currentload_nice: result.currentload_nice,
currentload_idle: result.currentload_idle,
currentload_irq: result.currentload_irq,
raw_currentload: result.raw_currentload,
raw_currentload_user: result.raw_currentload_user,
raw_currentload_system: result.raw_currentload_system,
raw_currentload_nice: result.raw_currentload_nice,
raw_currentload_idle: result.raw_currentload_idle,
raw_currentload_irq: result.raw_currentload_irq,
};
} else {
let cores = [];
for (let i = 0; i < _corecount; i++) {
cores[i] = {};
cores[i].load = _cpus[i].load / _cpus[i].currentTick * 100;
cores[i].load_user = _cpus[i].load_user / _cpus[i].currentTick * 100;
cores[i].load_system = _cpus[i].load_system / _cpus[i].currentTick * 100;
cores[i].load_nice = _cpus[i].load_nice / _cpus[i].currentTick * 100;
cores[i].load_idle = _cpus[i].load_idle / _cpus[i].currentTick * 100;
cores[i].load_irq = _cpus[i].load_irq / _cpus[i].currentTick * 100;
cores[i].raw_load = _cpus[i].load;
cores[i].raw_load_user = _cpus[i].load_user;
cores[i].raw_load_system = _cpus[i].load_system;
cores[i].raw_load_nice = _cpus[i].load_nice;
cores[i].raw_load_idle = _cpus[i].load_idle;
cores[i].raw_load_irq = _cpus[i].load_irq;
}
result = {
avgload: avgload,
currentload: _current_cpu.currentload,
currentload_user: _current_cpu.currentload_user,
currentload_system: _current_cpu.currentload_system,
currentload_nice: _current_cpu.currentload_nice,
currentload_idle: _current_cpu.currentload_idle,
currentload_irq: _current_cpu.currentload_irq,
raw_currentload: _current_cpu.raw_currentload,
raw_currentload_user: _current_cpu.raw_currentload_user,
raw_currentload_system: _current_cpu.raw_currentload_system,
raw_currentload_nice: _current_cpu.raw_currentload_nice,
raw_currentload_idle: _current_cpu.raw_currentload_idle,
raw_currentload_irq: _current_cpu.raw_currentload_irq,
cpus: cores
};
}
resolve(result);
});
});
}
function currentLoad(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
getLoad().then(result => {
if (callback) { callback(result); }
resolve(result);
});
});
});
}
exports.currentLoad = currentLoad;
// --------------------------
// PS - full load
// since bootup
function getFullLoad() {
return new Promise((resolve) => {
process.nextTick(() => {
const cpus = os.cpus();
let totalUser = 0;
let totalSystem = 0;
let totalNice = 0;
let totalIrq = 0;
let totalIdle = 0;
for (let i = 0, len = cpus.length; i < len; i++) {
const cpu = cpus[i].times;
totalUser += cpu.user;
totalSystem += cpu.sys;
totalNice += cpu.nice;
totalIrq += cpu.irq;
totalIdle += cpu.idle;
}
let totalTicks = totalIdle + totalIrq + totalNice + totalSystem + totalUser;
let result = (totalTicks - totalIdle) / totalTicks * 100.0;
resolve(result);
});
});
}
function fullLoad(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
getFullLoad().then(result => {
if (callback) { callback(result); }
resolve(result);
});
});
});
}
exports.fullLoad = fullLoad;
'use strict';
// @ts-check
// ==================================================================================
// docker.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 13. Docker
// ----------------------------------------------------------------------------------
const util = require('./util');
const DockerSocket = require('./dockerSocket');
let _platform = process.platform;
const _windows = (_platform === 'win32');
let _docker_container_stats = {};
let _docker_socket;
let _docker_last_read = 0;
// --------------------------
// get containers (parameter all: get also inactive/exited containers)
function dockerInfo(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
if (!_docker_socket) {
_docker_socket = new DockerSocket();
}
const result = {};
_docker_socket.getInfo(data => {
result.id = data.ID;
result.containers = data.Containers;
result.containersRunning = data.ContainersRunning;
result.containersPaused = data.ContainersPaused;
result.containersStopped = data.ContainersStopped;
result.images = data.Images;
result.driver = data.Driver;
result.memoryLimit = data.MemoryLimit;
result.swapLimit = data.SwapLimit;
result.kernelMemory = data.KernelMemory;
result.cpuCfsPeriod = data.CpuCfsPeriod;
result.cpuCfsQuota = data.CpuCfsQuota;
result.cpuShares = data.CPUShares;
result.cpuSet = data.CPUSet;
result.ipv4Forwarding = data.IPv4Forwarding;
result.bridgeNfIptables = data.BridgeNfIptables;
result.bridgeNfIp6tables = data.BridgeNfIp6tables;
result.debug = data.Debug;
result.nfd = data.NFd;
result.oomKillDisable = data.OomKillDisable;
result.ngoroutines = data.NGoroutines;
result.systemTime = data.SystemTime;
result.loggingDriver = data.LoggingDriver;
result.cgroupDriver = data.CgroupDriver;
result.nEventsListener = data.NEventsListener;
result.kernelVersion = data.KernelVersion;
result.pperatingSystem = data.OperatingSystem;
result.osType = data.OSType;
result.architecture = data.Architecture;
result.ncpu = data.NCPU;
result.memTotal = data.MemTotal;
result.dockerRootDir = data.DockerRootDir;
result.httpProxy = data.HttpProxy;
result.httpsProxy = data.HttpsProxy;
result.noProxy = data.NoProxy;
result.name = data.Name;
result.labels = data.Labels;
result.experimentalBuild = data.ExperimentalBuild;
result.serverVersion = data.ServerVersion;
result.clusterStore = data.ClusterStore;
result.clusterAdvertise = data.ClusterAdvertise;
result.defaultRuntime = data.DefaultRuntime;
result.liveRestoreEnabled = data.LiveRestoreEnabled;
result.isolation = data.Isolation;
result.initBinary = data.InitBinary;
result.productLicense = data.ProductLicense;
if (callback) { callback(result); }
resolve(result);
});
});
});
}
exports.dockerInfo = dockerInfo;
function dockerContainers(all, callback) {
function inContainers(containers, id) {
let filtered = containers.filter(obj => {
/**
* @namespace
* @property {string} Id
*/
return (obj.Id && (obj.Id === id));
});
return (filtered.length > 0);
}
// fallback - if only callback is given
if (util.isFunction(all) && !callback) {
callback = all;
all = false;
}
all = all || false;
let result = [];
return new Promise((resolve) => {
process.nextTick(() => {
if (!_docker_socket) {
_docker_socket = new DockerSocket();
}
const workload = [];
_docker_socket.listContainers(all, data => {
let docker_containers = {};
try {
docker_containers = data;
if (docker_containers && Object.prototype.toString.call(docker_containers) === '[object Array]' && docker_containers.length > 0) {
// GC in _docker_container_stats
for (let key in _docker_container_stats) {
if (_docker_container_stats.hasOwnProperty(key)) {
if (!inContainers(docker_containers, key)) delete _docker_container_stats[key];
}
}
docker_containers.forEach(function (element) {
if (element.Names && Object.prototype.toString.call(element.Names) === '[object Array]' && element.Names.length > 0) {
element.Name = element.Names[0].replace(/^\/|\/$/g, '');
}
workload.push(dockerContainerInspect(element.Id.trim(), element));
// result.push({
// id: element.Id,
// name: element.Name,
// image: element.Image,
// imageID: element.ImageID,
// command: element.Command,
// created: element.Created,
// state: element.State,
// ports: element.Ports,
// mounts: element.Mounts,
// // hostconfig: element.HostConfig,
// // network: element.NetworkSettings
// });
});
if (workload.length) {
Promise.all(
workload
).then(data => {
if (callback) { callback(data); }
resolve(data);
});
} else {
if (callback) { callback(result); }
resolve(result);
}
}
} catch (err) {
// GC in _docker_container_stats
for (let key in _docker_container_stats) {
if (_docker_container_stats.hasOwnProperty(key)) {
if (!inContainers(docker_containers, key)) delete _docker_container_stats[key];
}
}
if (callback) { callback(result); }
resolve(result);
}
});
});
});
}
// --------------------------
// container inspect (for one container)
function dockerContainerInspect(containerID, payload) {
containerID = containerID || '';
return new Promise((resolve) => {
process.nextTick(() => {
if (containerID) {
if (!_docker_socket) {
_docker_socket = new DockerSocket();
}
_docker_socket.getInspect(containerID.trim(), data => {
try {
resolve({
id: payload.Id,
name: payload.Name,
image: payload.Image,
imageID: payload.ImageID,
command: payload.Command,
created: payload.Created,
started: data.State && data.State.StartedAt ? Math.round(new Date(data.State.StartedAt).getTime() / 1000) : 0,
finished: data.State && data.State.FinishedAt && !data.State.FinishedAt.startsWith('0001-01-01') ? Math.round(new Date(data.State.FinishedAt).getTime() / 1000) : 0,
createdAt: data.Created ? data.Created : '',
startedAt: data.State && data.State.StartedAt ? data.State.StartedAt : '',
finishedAt: data.State && data.State.FinishedAt && !data.State.FinishedAt.startsWith('0001-01-01') ? data.State.FinishedAt : '',
state: payload.State,
restartCount: data.RestartCount || 0,
platform: data.Platform || '',
driver: data.Driver || '',
ports: payload.Ports,
mounts: payload.Mounts,
// hostconfig: payload.HostConfig,
// network: payload.NetworkSettings
});
} catch (err) {
resolve();
}
});
} else {
resolve();
}
});
});
}
exports.dockerContainers = dockerContainers;
// --------------------------
// helper functions for calculation of docker stats
function docker_calcCPUPercent(cpu_stats, precpu_stats) {
/**
* @namespace
* @property {object} cpu_usage
* @property {number} cpu_usage.total_usage
* @property {number} system_cpu_usage
* @property {object} cpu_usage
* @property {Array} cpu_usage.percpu_usage
*/
if (!_windows) {
let cpuPercent = 0.0;
// calculate the change for the cpu usage of the container in between readings
let cpuDelta = cpu_stats.cpu_usage.total_usage - precpu_stats.cpu_usage.total_usage;
// calculate the change for the entire system between readings
let systemDelta = cpu_stats.system_cpu_usage - precpu_stats.system_cpu_usage;
if (systemDelta > 0.0 && cpuDelta > 0.0) {
// calculate the change for the cpu usage of the container in between readings
cpuPercent = (cpuDelta / systemDelta) * cpu_stats.cpu_usage.percpu_usage.length * 100.0;
}
return cpuPercent;
} else {
let nanoSecNow = util.nanoSeconds();
let cpuPercent = 0.0;
if (_docker_last_read > 0) {
let possIntervals = (nanoSecNow - _docker_last_read); // / 100 * os.cpus().length;
let intervalsUsed = cpu_stats.cpu_usage.total_usage - precpu_stats.cpu_usage.total_usage;
if (possIntervals > 0) {
cpuPercent = 100.0 * intervalsUsed / possIntervals;
}
}
_docker_last_read = nanoSecNow;
return cpuPercent;
}
}
function docker_calcNetworkIO(networks) {
let rx;
let tx;
for (let key in networks) {
// skip loop if the property is from prototype
if (!networks.hasOwnProperty(key)) continue;
/**
* @namespace
* @property {number} rx_bytes
* @property {number} tx_bytes
*/
let obj = networks[key];
rx = +obj.rx_bytes;
tx = +obj.tx_bytes;
}
return {
rx: rx,
tx: tx
};
}
function docker_calcBlockIO(blkio_stats) {
let result = {
r: 0,
w: 0
};
/**
* @namespace
* @property {Array} io_service_bytes_recursive
*/
if (blkio_stats && blkio_stats.io_service_bytes_recursive && Object.prototype.toString.call(blkio_stats.io_service_bytes_recursive) === '[object Array]' && blkio_stats.io_service_bytes_recursive.length > 0) {
blkio_stats.io_service_bytes_recursive.forEach(function (element) {
/**
* @namespace
* @property {string} op
* @property {number} value
*/
if (element.op && element.op.toLowerCase() === 'read' && element.value) {
result.r += element.value;
}
if (element.op && element.op.toLowerCase() === 'write' && element.value) {
result.w += element.value;
}
});
}
return result;
}
function dockerContainerStats(containerIDs, callback) {
let containerArray = [];
// fallback - if only callback is given
if (util.isFunction(containerIDs) && !callback) {
callback = containerIDs;
containerArray = ['*'];
} else {
containerIDs = containerIDs || '*';
containerIDs = containerIDs.trim().toLowerCase().replace(/,+/g, '|');
containerArray = containerIDs.split('|');
}
return new Promise((resolve) => {
process.nextTick(() => {
const result = [];
const workload = [];
if (containerArray.length && containerArray[0].trim() === '*') {
containerArray = [];
dockerContainers().then(allContainers => {
for (let container of allContainers) {
containerArray.push(container.id);
}
dockerContainerStats(containerArray.join(',')).then(result => {
if (callback) { callback(result); }
resolve(result);
});
});
} else {
for (let containerID of containerArray) {
workload.push(dockerContainerStatsSingle(containerID.trim()));
}
if (workload.length) {
Promise.all(
workload
).then(data => {
if (callback) { callback(data); }
resolve(data);
});
} else {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
// --------------------------
// container stats (for one container)
function dockerContainerStatsSingle(containerID) {
containerID = containerID || '';
let result = {
id: containerID,
mem_usage: 0,
mem_limit: 0,
mem_percent: 0,
cpu_percent: 0,
pids: 0,
netIO: {
rx: 0,
wx: 0
},
blockIO: {
r: 0,
w: 0
}
};
return new Promise((resolve) => {
process.nextTick(() => {
if (containerID) {
if (!_docker_socket) {
_docker_socket = new DockerSocket();
}
_docker_socket.getInspect(containerID, dataInspect => {
try {
_docker_socket.getStats(containerID, data => {
try {
let stats = data;
/**
* @namespace
* @property {Object} memory_stats
* @property {number} memory_stats.usage
* @property {number} memory_stats.limit
* @property {Object} cpu_stats
* @property {Object} pids_stats
* @property {number} pids_stats.current
* @property {Object} networks
* @property {Object} blkio_stats
*/
if (!stats.message) {
result.mem_usage = (stats.memory_stats && stats.memory_stats.usage ? stats.memory_stats.usage : 0);
result.mem_limit = (stats.memory_stats && stats.memory_stats.limit ? stats.memory_stats.limit : 0);
result.mem_percent = (stats.memory_stats && stats.memory_stats.usage && stats.memory_stats.limit ? stats.memory_stats.usage / stats.memory_stats.limit * 100.0 : 0);
result.cpu_percent = (stats.cpu_stats && stats.precpu_stats ? docker_calcCPUPercent(stats.cpu_stats, stats.precpu_stats) : 0);
result.pids = (stats.pids_stats && stats.pids_stats.current ? stats.pids_stats.current : 0);
result.restartCount = (dataInspect.RestartCount ? dataInspect.RestartCount : 0);
if (stats.networks) result.netIO = docker_calcNetworkIO(stats.networks);
if (stats.blkio_stats) result.blockIO = docker_calcBlockIO(stats.blkio_stats);
result.cpu_stats = (stats.cpu_stats ? stats.cpu_stats : {});
result.precpu_stats = (stats.precpu_stats ? stats.precpu_stats : {});
result.memory_stats = (stats.memory_stats ? stats.memory_stats : {});
result.networks = (stats.networks ? stats.networks : {});
}
} catch (err) {
util.noop();
}
// }
resolve(result);
});
} catch (err) {
util.noop();
}
});
} else {
resolve(result);
}
});
});
}
exports.dockerContainerStats = dockerContainerStats;
// --------------------------
// container processes (for one container)
function dockerContainerProcesses(containerID, callback) {
containerID = containerID || '';
let result = [];
return new Promise((resolve) => {
process.nextTick(() => {
if (containerID) {
if (!_docker_socket) {
_docker_socket = new DockerSocket();
}
_docker_socket.getProcesses(containerID, data => {
/**
* @namespace
* @property {Array} Titles
* @property {Array} Processes
**/
try {
if (data && data.Titles && data.Processes) {
let titles = data.Titles.map(function (value) {
return value.toUpperCase();
});
let pos_pid = titles.indexOf('PID');
let pos_ppid = titles.indexOf('PPID');
let pos_pgid = titles.indexOf('PGID');
let pos_vsz = titles.indexOf('VSZ');
let pos_time = titles.indexOf('TIME');
let pos_elapsed = titles.indexOf('ELAPSED');
let pos_ni = titles.indexOf('NI');
let pos_ruser = titles.indexOf('RUSER');
let pos_user = titles.indexOf('USER');
let pos_rgroup = titles.indexOf('RGROUP');
let pos_group = titles.indexOf('GROUP');
let pos_stat = titles.indexOf('STAT');
let pos_rss = titles.indexOf('RSS');
let pos_command = titles.indexOf('COMMAND');
data.Processes.forEach(process => {
result.push({
pid_host: (pos_pid >= 0 ? process[pos_pid] : ''),
ppid: (pos_ppid >= 0 ? process[pos_ppid] : ''),
pgid: (pos_pgid >= 0 ? process[pos_pgid] : ''),
user: (pos_user >= 0 ? process[pos_user] : ''),
ruser: (pos_ruser >= 0 ? process[pos_ruser] : ''),
group: (pos_group >= 0 ? process[pos_group] : ''),
rgroup: (pos_rgroup >= 0 ? process[pos_rgroup] : ''),
stat: (pos_stat >= 0 ? process[pos_stat] : ''),
time: (pos_time >= 0 ? process[pos_time] : ''),
elapsed: (pos_elapsed >= 0 ? process[pos_elapsed] : ''),
nice: (pos_ni >= 0 ? process[pos_ni] : ''),
rss: (pos_rss >= 0 ? process[pos_rss] : ''),
vsz: (pos_vsz >= 0 ? process[pos_vsz] : ''),
command: (pos_command >= 0 ? process[pos_command] : '')
});
});
}
} catch (err) {
util.noop();
}
if (callback) { callback(result); }
resolve(result);
});
} else {
if (callback) { callback(result); }
resolve(result);
}
});
});
}
exports.dockerContainerProcesses = dockerContainerProcesses;
function dockerAll(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
dockerContainers(true).then(result => {
if (result && Object.prototype.toString.call(result) === '[object Array]' && result.length > 0) {
let l = result.length;
result.forEach(function (element) {
dockerContainerStats(element.id).then(res => {
// include stats in array
element.mem_usage = res[0].mem_usage;
element.mem_limit = res[0].mem_limit;
element.mem_percent = res[0].mem_percent;
element.cpu_percent = res[0].cpu_percent;
element.pids = res[0].pids;
element.netIO = res[0].netIO;
element.blockIO = res[0].blockIO;
element.cpu_stats = res[0].cpu_stats;
element.precpu_stats = res[0].precpu_stats;
element.memory_stats = res[0].memory_stats;
element.networks = res[0].networks;
dockerContainerProcesses(element.id).then(processes => {
element.processes = processes;
l -= 1;
if (l === 0) {
if (callback) { callback(result); }
resolve(result);
}
});
// all done??
});
});
} else {
if (callback) { callback(result); }
resolve(result);
}
});
});
});
}
exports.dockerAll = dockerAll;
'use strict';
// @ts-check
// ==================================================================================
// dockerSockets.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 13. DockerSockets
// ----------------------------------------------------------------------------------
const net = require('net');
const isWin = require('os').type() === 'Windows_NT';
const socketPath = isWin ? '//./pipe/docker_engine' : '/var/run/docker.sock';
class DockerSocket {
getInfo(callback) {
try {
let socket = net.createConnection({ path: socketPath });
let alldata = '';
let data;
socket.on('connect', () => {
socket.write('GET http:/info HTTP/1.0\r\n\r\n');
});
socket.on('data', data => {
alldata = alldata + data.toString();
});
socket.on('error', () => {
socket = false;
callback({});
});
socket.on('end', () => {
let startbody = alldata.indexOf('\r\n\r\n');
alldata = alldata.substring(startbody + 4);
socket = false;
try {
data = JSON.parse(alldata);
callback(data);
} catch (err) {
callback({});
}
});
} catch (err) {
callback({});
}
}
listContainers(all, callback) {
try {
let socket = net.createConnection({ path: socketPath });
let alldata = '';
let data;
socket.on('connect', () => {
socket.write('GET http:/containers/json' + (all ? '?all=1' : '') + ' HTTP/1.0\r\n\r\n');
});
socket.on('data', data => {
alldata = alldata + data.toString();
});
socket.on('error', () => {
socket = false;
callback({});
});
socket.on('end', () => {
let startbody = alldata.indexOf('\r\n\r\n');
alldata = alldata.substring(startbody + 4);
socket = false;
try {
data = JSON.parse(alldata);
callback(data);
} catch (err) {
callback({});
}
});
} catch (err) {
callback({});
}
}
getStats(id, callback) {
id = id || '';
if (id) {
try {
let socket = net.createConnection({ path: socketPath });
let alldata = '';
let data;
socket.on('connect', () => {
socket.write('GET http:/containers/' + id + '/stats?stream=0 HTTP/1.0\r\n\r\n');
});
socket.on('data', data => {
alldata = alldata + data.toString();
});
socket.on('error', () => {
socket = false;
callback({});
});
socket.on('end', () => {
let startbody = alldata.indexOf('\r\n\r\n');
alldata = alldata.substring(startbody + 4);
socket = false;
try {
data = JSON.parse(alldata);
callback(data);
} catch (err) {
callback({});
}
});
} catch (err) {
callback({});
}
} else {
callback({});
}
}
getInspect(id, callback) {
id = id || '';
if (id) {
try {
let socket = net.createConnection({ path: socketPath });
let alldata = '';
let data;
socket.on('connect', () => {
socket.write('GET http:/containers/' + id + '/json?stream=0 HTTP/1.0\r\n\r\n');
});
socket.on('data', data => {
alldata = alldata + data.toString();
});
socket.on('error', () => {
socket = false;
callback({});
});
socket.on('end', () => {
let startbody = alldata.indexOf('\r\n\r\n');
alldata = alldata.substring(startbody + 4);
socket = false;
try {
data = JSON.parse(alldata);
callback(data);
} catch (err) {
callback({});
}
});
} catch (err) {
callback({});
}
} else {
callback({});
}
}
getProcesses(id, callback) {
id = id || '';
if (id) {
try {
let socket = net.createConnection({ path: socketPath });
let alldata = '';
let data;
socket.on('connect', () => {
socket.write('GET http:/containers/' + id + '/top?ps_args=-opid,ppid,pgid,vsz,time,etime,nice,ruser,user,rgroup,group,stat,rss,args HTTP/1.0\r\n\r\n');
});
socket.on('data', data => {
alldata = alldata + data.toString();
});
socket.on('error', () => {
socket = false;
callback({});
});
socket.on('end', () => {
let startbody = alldata.indexOf('\r\n\r\n');
alldata = alldata.substring(startbody + 4);
socket = false;
try {
data = JSON.parse(alldata);
callback(data);
} catch (err) {
callback({});
}
});
} catch (err) {
callback({});
}
} else {
callback({});
}
}
}
module.exports = DockerSocket;
'use strict';
// @ts-check
// ==================================================================================
// filesystem.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 8. File System
// ----------------------------------------------------------------------------------
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;
const util = require('./util');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
const NOT_SUPPORTED = 'not supported';
let _fs_speed = {};
let _disk_io = {};
// --------------------------
// FS - mounted file systems
function fsSize(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let data = [];
if (_linux || _freebsd || _openbsd || _netbsd || _darwin) {
let cmd = '';
if (_darwin) cmd = 'df -lkP | grep ^/';
if (_linux) cmd = 'df -lkPT | grep ^/';
if (_freebsd || _openbsd || _netbsd) cmd = 'df -lkPT';
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
//lines.splice(0, 1);
lines.forEach(function (line) {
if (line !== '') {
line = line.replace(/ +/g, ' ').split(' ');
if (line && (line[0].startsWith('/')) || (line[6] && line[6] === '/')) {
data.push({
'fs': line[0],
'type': ((_linux || _freebsd || _openbsd || _netbsd) ? line[1] : 'HFS'),
'size': parseInt(((_linux || _freebsd || _openbsd || _netbsd) ? line[2] : line[1])) * 1024,
'used': parseInt(((_linux || _freebsd || _openbsd || _netbsd) ? line[3] : line[2])) * 1024,
'use': parseFloat((100.0 * ((_linux || _freebsd || _openbsd || _netbsd) ? line[3] : line[2]) / ((_linux || _freebsd || _openbsd || _netbsd) ? line[2] : line[1])).toFixed(2)),
'mount': line[line.length - 1]
});
}
}
});
}
if (callback) {
callback(data);
}
resolve(data);
});
}
if (_sunos) {
if (callback) { callback(data); }
resolve(data);
}
if (_windows) {
try {
util.wmic('logicaldisk get Caption,FileSystem,FreeSpace,Size').then((stdout) => {
let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0);
lines.forEach(function (line) {
if (line !== '') {
line = line.trim().split(/\s\s+/);
data.push({
'fs': line[0],
'type': line[1],
'size': parseInt(line[3]),
'used': parseInt(line[3]) - parseInt(line[2]),
'use': parseFloat((100.0 * (parseInt(line[3]) - parseInt(line[2]))) / parseInt(line[3])),
'mount': line[0]
});
}
});
if (callback) {
callback(data);
}
resolve(data);
});
} catch (e) {
if (callback) { callback(data); }
resolve(data);
}
}
});
});
}
exports.fsSize = fsSize;
// --------------------------
// FS - open files count
function fsOpenFiles(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
const result = {
max: -1,
allocated: -1,
available: -1
};
if (_freebsd || _openbsd || _netbsd || _darwin) {
let cmd = 'sysctl -a | grep \'kern.*files\'';
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result.max = parseInt(util.getValue(lines, 'kern.maxfiles', ':'), 10);
result.allocated = parseInt(util.getValue(lines, 'kern.num_files', ':'), 10);
}
if (callback) {
callback(result);
}
resolve(result);
});
}
if (_linux) {
let cmd = 'cat /proc/sys/fs/file-nr';
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
if (lines[0]) {
const parts = lines[0].replace(/\s+/g, ' ').split(' ');
if (parts.length === 3) {
result.allocated = parseInt(parts[0], 10);
result.available = parseInt(parts[1], 10);
result.max = parseInt(parts[2], 10);
}
}
}
if (callback) {
callback(result);
}
resolve(result);
});
}
if (_sunos) {
if (callback) { callback(result); }
resolve(result);
}
if (_windows) {
if (callback) { callback(result); }
resolve(result);
}
});
});
}
exports.fsOpenFiles = fsOpenFiles;
// --------------------------
// disks
function parseBytes(s) {
return parseInt(s.substr(s.indexOf(' (') + 2, s.indexOf(' Bytes)') - 10));
}
function parseDevices(lines) {
let devices = [];
let i = 0;
lines.forEach(line => {
if (line.length > 0) {
if (line[0] === '*') {
i++;
} else {
let parts = line.split(':');
if (parts.length > 1) {
if (!devices[i]) devices[i] = {
name: '',
identifier: '',
type: 'disk',
fstype: '',
mount: '',
size: 0,
physical: 'HDD',
uuid: '',
label: '',
model: '',
serial: '',
removable: false,
protocol: ''
};
parts[0] = parts[0].trim().toUpperCase().replace(/ +/g, '');
parts[1] = parts[1].trim();
if ('DEVICEIDENTIFIER' === parts[0]) devices[i].identifier = parts[1];
if ('DEVICENODE' === parts[0]) devices[i].name = parts[1];
if ('VOLUMENAME' === parts[0]) {
if (parts[1].indexOf('Not applicable') === -1) devices[i].label = parts[1];
}
if ('PROTOCOL' === parts[0]) devices[i].protocol = parts[1];
if ('DISKSIZE' === parts[0]) devices[i].size = parseBytes(parts[1]);
if ('FILESYSTEMPERSONALITY' === parts[0]) devices[i].fstype = parts[1];
if ('MOUNTPOINT' === parts[0]) devices[i].mount = parts[1];
if ('VOLUMEUUID' === parts[0]) devices[i].uuid = parts[1];
if ('READ-ONLYMEDIA' === parts[0] && parts[1] === 'Yes') devices[i].physical = 'CD/DVD';
if ('SOLIDSTATE' === parts[0] && parts[1] === 'Yes') devices[i].physical = 'SSD';
if ('VIRTUAL' === parts[0]) devices[i].type = 'virtual';
if ('REMOVABLEMEDIA' === parts[0]) devices[i].removable = (parts[1] === 'Removable');
if ('PARTITIONTYPE' === parts[0]) devices[i].type = 'part';
if ('DEVICE/MEDIANAME' === parts[0]) devices[i].model = parts[1];
}
}
}
});
return devices;
}
function parseBlk(lines) {
let data = [];
lines.filter(line => line !== '').forEach((line) => {
line = util.decodeEscapeSequence(line);
line = line.replace(/\\/g, '\\\\');
let disk = JSON.parse(line);
data.push({
'name': disk.name,
'type': disk.type,
'fstype': disk.fstype,
'mount': disk.mountpoint,
'size': parseInt(disk.size),
'physical': (disk.type === 'disk' ? (disk.rota === '0' ? 'SSD' : 'HDD') : (disk.type === 'rom' ? 'CD/DVD' : '')),
'uuid': disk.uuid,
'label': disk.label,
'model': disk.model,
'serial': disk.serial,
'removable': disk.rm === '1',
'protocol': disk.tran
});
});
data = util.unique(data);
data = util.sortByKey(data, ['type', 'name']);
return data;
}
function blkStdoutToObject(stdout) {
return stdout.toString()
.replace(/NAME=/g, '{"name":')
.replace(/FSTYPE=/g, ',"fstype":')
.replace(/TYPE=/g, ',"type":')
.replace(/SIZE=/g, ',"size":')
.replace(/MOUNTPOINT=/g, ',"mountpoint":')
.replace(/UUID=/g, ',"uuid":')
.replace(/ROTA=/g, ',"rota":')
.replace(/RO=/g, ',"ro":')
.replace(/RM=/g, ',"rm":')
.replace(/TRAN=/g, ',"tran":')
.replace(/SERIAL=/g, ',"serial":')
.replace(/LABEL=/g, ',"label":')
.replace(/MODEL=/g, ',"model":')
.replace(/OWNER=/g, ',"owner":')
.replace(/\n/g, '}\n');
}
function blockDevices(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let data = [];
if (_linux) {
// see https://wiki.ubuntuusers.de/lsblk/
// exec("lsblk -bo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,TRAN,SERIAL,LABEL,MODEL,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,SCHED,RQ-SIZE,RA,WSAME", function (error, stdout) {
exec('lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,TRAN,SERIAL,LABEL,MODEL,OWNER', function (error, stdout) {
if (!error) {
let lines = blkStdoutToObject(stdout).split('\n');
data = parseBlk(lines);
if (callback) {
callback(data);
}
resolve(data);
} else {
exec('lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,LABEL,MODEL,OWNER', function (error, stdout) {
if (!error) {
let lines = blkStdoutToObject(stdout).split('\n');
data = parseBlk(lines);
}
if (callback) {
callback(data);
}
resolve(data);
});
}
});
}
if (_darwin) {
exec('diskutil info -all', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
// parse lines into temp array of devices
data = parseDevices(lines);
}
if (callback) {
callback(data);
}
resolve(data);
});
}
if (_sunos) {
if (callback) { callback(data); }
resolve(data);
}
if (_windows) {
let drivetypes = ['Unknown', 'NoRoot', 'Removable', 'Local', 'Network', 'CD/DVD', 'RAM'];
try {
util.wmic('logicaldisk get Caption,Description,DeviceID,DriveType,FileSystem,FreeSpace,Name,Size,VolumeName,VolumeSerialNumber /value').then((stdout, error) => {
if (!error) {
let devices = stdout.toString().split(/\n\s*\n/);
devices.forEach(function (device) {
let lines = device.split('\r\n');
let drivetype = util.getValue(lines, 'drivetype', '=');
if (drivetype) {
data.push({
name: util.getValue(lines, 'name', '='),
identifier: util.getValue(lines, 'caption', '='),
type: 'disk',
fstype: util.getValue(lines, 'filesystem', '=').toLowerCase(),
mount: util.getValue(lines, 'caption', '='),
size: util.getValue(lines, 'size', '='),
physical: (drivetype >= 0 && drivetype <= 6) ? drivetypes[drivetype] : drivetypes[0],
uuid: util.getValue(lines, 'volumeserialnumber', '='),
label: util.getValue(lines, 'volumename', '='),
model: '',
serial: util.getValue(lines, 'volumeserialnumber', '='),
removable: drivetype === '2',
protocol: ''
});
}
});
}
if (callback) {
callback(data);
}
resolve(data);
});
} catch (e) {
if (callback) { callback(data); }
resolve(data);
}
}
});
});
}
exports.blockDevices = blockDevices;
// --------------------------
// FS - speed
function calcFsSpeed(rx, wx) {
let result = {
rx: 0,
wx: 0,
tx: 0,
rx_sec: -1,
wx_sec: -1,
tx_sec: -1,
ms: 0
};
if (_fs_speed && _fs_speed.ms) {
result.rx = rx;
result.wx = wx;
result.tx = result.rx + result.wx;
result.ms = Date.now() - _fs_speed.ms;
result.rx_sec = (result.rx - _fs_speed.bytes_read) / (result.ms / 1000);
result.wx_sec = (result.wx - _fs_speed.bytes_write) / (result.ms / 1000);
result.tx_sec = result.rx_sec + result.wx_sec;
_fs_speed.rx_sec = result.rx_sec;
_fs_speed.wx_sec = result.wx_sec;
_fs_speed.tx_sec = result.tx_sec;
_fs_speed.bytes_read = result.rx;
_fs_speed.bytes_write = result.wx;
_fs_speed.bytes_overall = result.rx + result.wx;
_fs_speed.ms = Date.now();
_fs_speed.last_ms = result.ms;
} else {
result.rx = rx;
result.wx = wx;
result.tx = result.rx + result.wx;
_fs_speed.rx_sec = -1;
_fs_speed.wx_sec = -1;
_fs_speed.tx_sec = -1;
_fs_speed.bytes_read = result.rx;
_fs_speed.bytes_write = result.wx;
_fs_speed.bytes_overall = result.rx + result.wx;
_fs_speed.ms = Date.now();
_fs_speed.last_ms = 0;
}
return result;
}
function fsStats(callback) {
return new Promise((resolve, reject) => {
process.nextTick(() => {
if (_windows) {
let error = new Error(NOT_SUPPORTED);
if (callback) {
callback(NOT_SUPPORTED);
}
reject(error);
}
let result = {
rx: 0,
wx: 0,
tx: 0,
rx_sec: -1,
wx_sec: -1,
tx_sec: -1,
ms: 0
};
let rx = 0;
let wx = 0;
if ((_fs_speed && !_fs_speed.ms) || (_fs_speed && _fs_speed.ms && Date.now() - _fs_speed.ms >= 500)) {
if (_linux) {
// exec("df -k | grep /dev/", function(error, stdout) {
exec('lsblk | grep /', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
let fs_filter = [];
lines.forEach(function (line) {
if (line !== '') {
line = line.replace(/[├─│└]+/g, '').trim().split(' ');
if (fs_filter.indexOf(line[0]) === -1) fs_filter.push(line[0]);
}
});
let output = fs_filter.join('|');
exec('cat /proc/diskstats | egrep "' + output + '"', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
line = line.trim();
if (line !== '') {
line = line.replace(/ +/g, ' ').split(' ');
rx += parseInt(line[5]) * 512;
wx += parseInt(line[9]) * 512;
}
});
result = calcFsSpeed(rx, wx);
}
if (callback) {
callback(result);
}
resolve(result);
});
} else {
if (callback) {
callback(result);
}
resolve(result);
}
});
}
if (_darwin) {
exec('ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n "/IOBlockStorageDriver/,/Statistics/p" | grep "Statistics" | tr -cd "01234567890,\n"', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
line = line.trim();
if (line !== '') {
line = line.split(',');
rx += parseInt(line[2]);
wx += parseInt(line[9]);
}
});
result = calcFsSpeed(rx, wx);
}
if (callback) {
callback(result);
}
resolve(result);
});
}
} else {
result.ms = _fs_speed.last_ms;
result.rx = _fs_speed.bytes_read;
result.wx = _fs_speed.bytes_write;
result.tx = _fs_speed.bytes_read + _fs_speed.bytes_write;
result.rx_sec = _fs_speed.rx_sec;
result.wx_sec = _fs_speed.wx_sec;
result.tx_sec = _fs_speed.tx_sec;
if (callback) {
callback(result);
}
resolve(result);
}
});
});
}
exports.fsStats = fsStats;
function calcDiskIO(rIO, wIO) {
let result = {
rIO: 0,
wIO: 0,
tIO: 0,
rIO_sec: -1,
wIO_sec: -1,
tIO_sec: -1,
ms: 0
};
if (_disk_io && _disk_io.ms) {
result.rIO = rIO;
result.wIO = wIO;
result.tIO = rIO + wIO;
result.ms = Date.now() - _disk_io.ms;
result.rIO_sec = (result.rIO - _disk_io.rIO) / (result.ms / 1000);
result.wIO_sec = (result.wIO - _disk_io.wIO) / (result.ms / 1000);
result.tIO_sec = result.rIO_sec + result.wIO_sec;
_disk_io.rIO = rIO;
_disk_io.wIO = wIO;
_disk_io.rIO_sec = result.rIO_sec;
_disk_io.wIO_sec = result.wIO_sec;
_disk_io.tIO_sec = result.tIO_sec;
_disk_io.last_ms = result.ms;
_disk_io.ms = Date.now();
} else {
result.rIO = rIO;
result.wIO = wIO;
result.tIO = rIO + wIO;
_disk_io.rIO = rIO;
_disk_io.wIO = wIO;
_disk_io.rIO_sec = -1;
_disk_io.wIO_sec = -1;
_disk_io.tIO_sec = -1;
_disk_io.last_ms = 0;
_disk_io.ms = Date.now();
}
return result;
}
function disksIO(callback) {
return new Promise((resolve, reject) => {
process.nextTick(() => {
if (_windows) {
let error = new Error(NOT_SUPPORTED);
if (callback) {
callback(NOT_SUPPORTED);
}
reject(error);
}
if (_sunos) {
let error = new Error(NOT_SUPPORTED);
if (callback) {
callback(NOT_SUPPORTED);
}
reject(error);
}
let result = {
rIO: 0,
wIO: 0,
tIO: 0,
rIO_sec: -1,
wIO_sec: -1,
tIO_sec: -1,
ms: 0
};
let rIO = 0;
let wIO = 0;
if ((_disk_io && !_disk_io.ms) || (_disk_io && _disk_io.ms && Date.now() - _disk_io.ms >= 500)) {
if (_linux || _freebsd || _openbsd || _netbsd) {
// prints Block layer statistics for all mounted volumes
// var cmd = "for mount in `lsblk | grep / | sed -r 's/│ └─//' | cut -d ' ' -f 1`; do cat /sys/block/$mount/stat | sed -r 's/ +/;/g' | sed -r 's/^;//'; done";
// var cmd = "for mount in `lsblk | grep / | sed 's/[│└─├]//g' | awk '{$1=$1};1' | cut -d ' ' -f 1 | sort -u`; do cat /sys/block/$mount/stat | sed -r 's/ +/;/g' | sed -r 's/^;//'; done";
let cmd = 'for mount in `lsblk | grep " disk " | sed "s/[│└─├]//g" | awk \'{$1=$1};1\' | cut -d " " -f 1 | sort -u`; do cat /sys/block/$mount/stat | sed -r "s/ +/;/g" | sed -r "s/^;//"; done';
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.split('\n');
lines.forEach(function (line) {
// ignore empty lines
if (!line) return;
// sum r/wIO of all disks to compute all disks IO
let stats = line.split(';');
rIO += parseInt(stats[0]);
wIO += parseInt(stats[4]);
});
result = calcDiskIO(rIO, wIO);
if (callback) {
callback(result);
}
resolve(result);
} else {
if (callback) {
callback(result);
}
resolve(result);
}
});
}
if (_darwin) {
exec('ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n "/IOBlockStorageDriver/,/Statistics/p" | grep "Statistics" | tr -cd "01234567890,\n"', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
line = line.trim();
if (line !== '') {
line = line.split(',');
rIO += parseInt(line[10]);
wIO += parseInt(line[0]);
}
});
result = calcDiskIO(rIO, wIO);
}
if (callback) {
callback(result);
}
resolve(result);
});
}
} else {
result.rIO = _disk_io.rIO;
result.wIO = _disk_io.wIO;
result.tIO = _disk_io.rIO + _disk_io.wIO;
result.ms = _disk_io.last_ms;
result.rIO_sec = _disk_io.rIO_sec;
result.wIO_sec = _disk_io.wIO_sec;
result.tIO_sec = _disk_io.tIO_sec;
if (callback) {
callback(result);
}
resolve(result);
}
});
});
}
exports.disksIO = disksIO;
function diskLayout(callback) {
function getVendorFromModel(model) {
const diskManufacturers = [
{ pattern: '^WESTERN.+', manufacturer: 'Western Digital' },
{ pattern: '^WDC.+', manufacturer: 'Western Digital' },
{ pattern: 'WD.+', manufacturer: 'Western Digital' },
{ pattern: '^TOSHIBA.+', manufacturer: 'Toshiba' },
{ pattern: '^HITACHI.+', manufacturer: 'Hitachi' },
{ pattern: '^IC.+', manufacturer: 'Hitachi' },
{ pattern: '^HTS.+', manufacturer: 'Hitachi' },
{ pattern: '^SANDISK.+', manufacturer: 'SanDisk' },
{ pattern: '^KINGSTON.+', manufacturer: 'Kingston Technonogy' },
{ pattern: '^SONY.+', manufacturer: 'Sony' },
{ pattern: '^TRANSCEND.+', manufacturer: 'Transcend' },
{ pattern: 'SAMSUNG.+', manufacturer: 'Samsung' },
{ pattern: '^ST(?!I\\ ).+', manufacturer: 'Seagate' },
{ pattern: '^STI\\ .+', manufacturer: 'SimpleTech' },
{ pattern: '^D...-.+', manufacturer: 'IBM' },
{ pattern: '^IBM.+', manufacturer: 'IBM' },
{ pattern: '^FUJITSU.+', manufacturer: 'Fujitsu' },
{ pattern: '^MP.+', manufacturer: 'Fujitsu' },
{ pattern: '^MK.+', manufacturer: 'Toshiba' },
{ pattern: '^MAXTOR.+', manufacturer: 'Maxtor' },
{ pattern: '^Pioneer.+', manufacturer: 'Pioneer' },
{ pattern: '^PHILIPS.+', manufacturer: 'Philips' },
{ pattern: '^QUANTUM.+', manufacturer: 'Quantum Technology' },
{ pattern: 'FIREBALL.+', manufacturer: 'Quantum Technology' },
{ pattern: '^VBOX.+', manufacturer: 'VirtualBox' },
{ pattern: 'CORSAIR.+', manufacturer: 'Corsair Components' },
{ pattern: 'CRUCIAL.+', manufacturer: 'Crucial' },
{ pattern: 'ECM.+', manufacturer: 'ECM' },
{ pattern: 'INTEL.+', manufacturer: 'INTEL' },
];
let result = '';
model = model.toUpperCase();
diskManufacturers.forEach((manufacturer) => {
const re = RegExp(manufacturer.pattern);
if (re.test(model)) { result = manufacturer.manufacturer; }
});
return result;
}
return new Promise((resolve) => {
process.nextTick(() => {
let result = [];
let cmd = '';
if (_linux) {
exec('export LC_ALL=C; lsblk -ablJO; unset LC_ALL', function (error, stdout) {
if (!error) {
try {
const out = stdout.toString().trim();
const outJSON = JSON.parse(out);
if (outJSON && outJSON.hasOwnProperty('blockdevices')) {
let devices = outJSON.blockdevices.filter(item => { return item.group === 'disk' && item.size > 0 && item.model !== null; });
devices.forEach((device) => {
let mediumType = '';
const BSDName = '/dev/' + device.name;
const logical = device.name;
try {
mediumType = execSync('cat /sys/block/' + logical + '/queue/rotational').toString().split('\n')[0];
} catch (e) {
util.noop();
}
let interfaceType = device.tran ? device.tran.toUpperCase().trim() : '';
if (interfaceType === 'NVME') {
mediumType = '2';
interfaceType = 'PCIe';
}
result.push({
device: BSDName,
type: (mediumType === '0' ? 'SSD' : (mediumType === '1' ? 'HD' : (mediumType === '2' ? 'NVMe' : (device.model && device.model.indexOf('SSD') > -1 ? 'SSD' : (device.model && device.model.indexOf('NVM') > -1 ? 'NVMe' : 'HD'))))),
name: device.model || '',
vendor: getVendorFromModel(device.model) || (device.vendor ? device.vendor.trim() : ''),
size: device.size || 0,
bytesPerSector: -1,
totalCylinders: -1,
totalHeads: -1,
totalSectors: -1,
totalTracks: -1,
tracksPerCylinder: -1,
sectorsPerTrack: -1,
firmwareRevision: device.rev ? device.rev.trim() : '',
serialNum: device.serial ? device.serial.trim() : '',
interfaceType: interfaceType,
smartStatus: 'unknown',
BSDName: BSDName
});
cmd = cmd + 'printf "\n' + BSDName + '|"; smartctl -H ' + BSDName + ' | grep overall;';
});
}
} catch (e) {
util.noop();
}
}
// lshw sometimes returns empty results, try lsblk
// check S.M.A.R.T. status
if (cmd) {
cmd = cmd + 'printf "\n"';
exec(cmd, function (error, stdout) {
let lines = stdout.toString().split('\n');
lines.forEach(line => {
if (line) {
let parts = line.split('|');
if (parts.length === 2) {
let BSDName = parts[0];
parts[1] = parts[1].trim();
let parts2 = parts[1].split(':');
if (parts2.length === 2) {
parts2[1] = parts2[1].trim();
let status = parts2[1].toLowerCase();
for (let i = 0; i < result.length; i++) {
if (result[i].BSDName === BSDName) {
result[i].smartStatus = (status === 'passed' ? 'Ok' : (status === 'failed!' ? 'Predicted Failure' : 'unknown'));
}
}
}
}
}
});
for (let i = 0; i < result.length; i++) {
delete result[i].BSDName;
}
if (callback) {
callback(result);
}
resolve(result);
});
} else {
for (let i = 0; i < result.length; i++) {
delete result[i].BSDName;
}
if (callback) {
callback(result);
}
resolve(result);
}
});
}
if (_freebsd || _openbsd || _netbsd) {
if (callback) { callback(result); }
resolve(result);
}
if (_sunos) {
if (callback) { callback(result); }
resolve(result);
}
if (_darwin) {
exec('system_profiler SPSerialATADataType SPNVMeDataType', function (error, stdout) {
if (!error) {
let parts = stdout.toString().split('NVMExpress:');
let devices = parts[0].split(' Physical Interconnect: ');
devices.shift();
devices.forEach(function (device) {
device = 'InterfaceType: ' + device;
let lines = device.split('\n');
const mediumType = util.getValue(lines, 'Medium Type', ':', true).trim();
const sizeStr = util.getValue(lines, 'capacity', ':', true).trim();
const BSDName = util.getValue(lines, 'BSD Name', ':', true).trim();
if (sizeStr) {
let sizeValue = 0;
if (sizeStr.indexOf('(') >= 0) {
sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, ''));
}
if (!sizeValue) {
sizeValue = parseInt(sizeStr);
}
if (sizeValue) {
result.push({
device: BSDName,
type: mediumType.startsWith('Solid') ? 'SSD' : 'HD',
name: util.getValue(lines, 'Model', ':', true).trim(),
vendor: getVendorFromModel(util.getValue(lines, 'Model', ':', true).trim()),
size: sizeValue,
bytesPerSector: -1,
totalCylinders: -1,
totalHeads: -1,
totalSectors: -1,
totalTracks: -1,
tracksPerCylinder: -1,
sectorsPerTrack: -1,
firmwareRevision: util.getValue(lines, 'Revision', ':', true).trim(),
serialNum: util.getValue(lines, 'Serial Number', ':', true).trim(),
interfaceType: util.getValue(lines, 'InterfaceType', ':', true).trim(),
smartStatus: 'unknown',
BSDName: BSDName
});
cmd = cmd + 'printf "\n' + BSDName + '|"; diskutil info /dev/' + BSDName + ' | grep SMART;';
}
}
});
if (parts.length > 1) {
let devices = parts[1].split('\n\n Capacity:');
devices.shift();
devices.forEach(function (device) {
device = '!Capacity: ' + device;
let lines = device.split('\n');
const linkWidth = util.getValue(lines, 'link width', ':', true).trim();
const sizeStr = util.getValue(lines, '!capacity', ':', true).trim();
const BSDName = util.getValue(lines, 'BSD Name', ':', true).trim();
if (sizeStr) {
let sizeValue = 0;
if (sizeStr.indexOf('(') >= 0) {
sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, ''));
}
if (!sizeValue) {
sizeValue = parseInt(sizeStr);
}
if (sizeValue) {
result.push({
device: BSDName,
type: 'NVMe',
name: util.getValue(lines, 'Model', ':', true).trim(),
vendor: getVendorFromModel(util.getValue(lines, 'Model', ':', true).trim()),
size: sizeValue,
bytesPerSector: -1,
totalCylinders: -1,
totalHeads: -1,
totalSectors: -1,
totalTracks: -1,
tracksPerCylinder: -1,
sectorsPerTrack: -1,
firmwareRevision: util.getValue(lines, 'Revision', ':', true).trim(),
serialNum: util.getValue(lines, 'Serial Number', ':', true).trim(),
interfaceType: ('PCIe ' + linkWidth).trim(),
smartStatus: 'unknown',
BSDName: BSDName
});
cmd = cmd + 'printf "\n' + BSDName + '|"; diskutil info /dev/' + BSDName + ' | grep SMART;';
}
}
});
}
}
if (cmd) {
cmd = cmd + 'printf "\n"';
exec(cmd, function (error, stdout) {
let lines = stdout.toString().split('\n');
lines.forEach(line => {
if (line) {
let parts = line.split('|');
if (parts.length === 2) {
let BSDName = parts[0];
parts[1] = parts[1].trim();
let parts2 = parts[1].split(':');
if (parts2.length === 2) {
parts2[1] = parts2[1].trim();
let status = parts2[1].toLowerCase();
for (let i = 0; i < result.length; i++) {
if (result[i].BSDName === BSDName) {
result[i].smartStatus = (status === 'not supported' ? 'not supported' : (status === 'verified' ? 'Ok' : (status === 'failing' ? 'Predicted Failure' : 'unknown')));
}
}
}
}
}
});
for (let i = 0; i < result.length; i++) {
delete result[i].BSDName;
}
if (callback) {
callback(result);
}
resolve(result);
});
} else {
for (let i = 0; i < result.length; i++) {
delete result[i].BSDName;
}
if (callback) {
callback(result);
}
resolve(result);
}
});
}
if (_windows) {
try {
util.wmic('diskdrive get /value').then((stdout, error) => {
if (!error) {
let devices = stdout.toString().split(/\n\s*\n/);
devices.forEach(function (device) {
let lines = device.split('\r\n');
const size = util.getValue(lines, 'Size', '=').trim();
const status = util.getValue(lines, 'Status', '=').trim().toLowerCase();
if (size) {
result.push({
device: '',
type: device.indexOf('SSD') > -1 ? 'SSD' : 'HD', // just a starting point ... better: MSFT_PhysicalDisk - Media Type ... see below
name: util.getValue(lines, 'Caption', '='),
vendor: util.getValue(lines, 'Manufacturer', '='),
size: parseInt(size),
bytesPerSector: parseInt(util.getValue(lines, 'BytesPerSector', '=')),
totalCylinders: parseInt(util.getValue(lines, 'TotalCylinders', '=')),
totalHeads: parseInt(util.getValue(lines, 'TotalHeads', '=')),
totalSectors: parseInt(util.getValue(lines, 'TotalSectors', '=')),
totalTracks: parseInt(util.getValue(lines, 'TotalTracks', '=')),
tracksPerCylinder: parseInt(util.getValue(lines, 'TracksPerCylinder', '=')),
sectorsPerTrack: parseInt(util.getValue(lines, 'SectorsPerTrack', '=')),
firmwareRevision: util.getValue(lines, 'FirmwareRevision', '=').trim(),
serialNum: util.getValue(lines, 'SerialNumber', '=').trim(),
interfaceType: util.getValue(lines, 'InterfaceType', '=').trim(),
smartStatus: (status === 'ok' ? 'Ok' : (status === 'degraded' ? 'Degraded' : (status === 'pred fail' ? 'Predicted Failure' : 'Unknown')))
});
}
});
util.powerShell('Get-PhysicalDisk | Format-List')
.then(data => {
let devices = data.split(/\n\s*\n/);
devices.forEach(function (device) {
let lines = device.split('\r\n');
const serialNum = util.getValue(lines, 'SerialNumber', ':').trim();
const name = util.getValue(lines, 'FriendlyName', ':').trim();
const size = util.getValue(lines, 'Size', ':').trim();
const interfaceType = util.getValue(lines, 'BusType', ':').trim();
let mediaType = util.getValue(lines, 'MediaType', ':').trim();
if (mediaType === '3' || mediaType === 'HDD') { mediaType = 'HD'; }
if (mediaType === '4') { mediaType = 'SSD'; }
if (mediaType === '5') { mediaType = 'SCM'; }
if (size) {
let i = util.findObjectByKey(result, 'serialNum', serialNum);
if (i === -1) {
i = util.findObjectByKey(result, 'name', name);
}
if (i != -1) {
result[i].type = mediaType;
result[i].interfaceType = interfaceType;
}
}
});
if (callback) {
callback(result);
}
resolve(result);
})
.catch(() => {
if (callback) {
callback(result);
}
resolve(result);
});
} else {
if (callback) {
callback(result);
}
resolve(result);
}
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.diskLayout = diskLayout;
'use strict';
// @ts-check
// ==================================================================================
// graphics.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 7. Graphics (controller, display)
// ----------------------------------------------------------------------------------
const os = require('os');
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;
const util = require('./util');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
let _resolutionx = 0;
let _resolutiony = 0;
let _pixeldepth = 0;
let _refreshrate = 0;
const videoTypes = {
'-2': 'UNINITIALIZED',
'-1': 'OTHER',
'0': 'HD15',
'1': 'SVIDEO',
'2': 'Composite video',
'3': 'Component video',
'4': 'DVI',
'5': 'HDMI',
'6': 'LVDS',
'8': 'D_JPN',
'9': 'SDI',
'10': 'DP',
'11': 'DP embedded',
'12': 'UDI',
'13': 'UDI embedded',
'14': 'SDTVDONGLE',
'15': 'MIRACAST',
'2147483648': 'INTERNAL'
};
function graphics(callback) {
function parseLinesDarwin(lines) {
let starts = [];
let level = -1;
let lastlevel = -1;
let controllers = [];
let displays = [];
let currentController = {
vendor: '',
model: '',
bus: '',
vram: -1,
vramDynamic: false
};
let currentDisplay = {
vendor: '',
model: '',
main: false,
builtin: false,
connection: '',
sizex: -1,
sizey: -1,
pixeldepth: -1,
resolutionx: -1,
resolutiony: -1,
currentResX: -1,
currentResY: -1,
positionX: 0,
positionY: 0,
currentRefreshRate: -1
};
for (let i = 0; i < lines.length; i++) {
if ('' !== lines[i].trim()) {
let start = lines[i].search(/\S|$/);
if (-1 === starts.indexOf(start)) {
starts.push(start);
}
level = starts.indexOf(start);
if (level < lastlevel) {
if (Object.keys(currentController).length > 0) {// just changed to Displays
controllers.push(currentController);
currentController = {
vendor: '',
model: '',
bus: '',
vram: -1,
vramDynamic: false
};
}
if (Object.keys(currentDisplay).length > 0) {// just changed to Displays
displays.push(currentDisplay);
currentDisplay = {
vendor: '',
model: '',
main: false,
builtin: false,
connection: '',
sizex: -1,
sizey: -1,
pixeldepth: -1,
resolutionx: -1,
resolutiony: -1,
currentResX: -1,
currentResY: -1,
positionX: 0,
positionY: 0,
currentRefreshRate: -1
};
}
}
lastlevel = level;
let parts = lines[i].split(':');
if (2 === level) { // grafics controller level
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('chipsetmodel') !== -1) currentController.model = parts[1].trim();
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('bus') !== -1) currentController.bus = parts[1].trim();
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('vendor') !== -1) currentController.vendor = parts[1].split('(')[0].trim();
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('vram(total)') !== -1) {
currentController.vram = parseInt(parts[1]); // in MB
currentController.vramDynamic = false;
}
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('vram(dynamic,max)') !== -1) {
currentController.vram = parseInt(parts[1]); // in MB
currentController.vramDynamic = true;
}
}
if (3 === level) { // display controller level
if (parts.length > 1 && '' === parts[1]) {
currentDisplay.vendor = '';
currentDisplay.model = parts[0].trim();
currentDisplay.main = false;
currentDisplay.builtin = false;
currentDisplay.connection = '';
currentDisplay.sizex = -1;
currentDisplay.sizey = -1;
currentDisplay.positionX = 0;
currentDisplay.positionY = 0;
currentDisplay.pixeldepth = -1;
}
}
if (4 === level) { // display controller details level
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('resolution') !== -1) {
let resolution = parts[1].split('x');
currentDisplay.resolutionx = (resolution.length > 1 ? parseInt(resolution[0]) : 0);
currentDisplay.resolutiony = (resolution.length > 1 ? parseInt(resolution[1]) : 0);
currentDisplay.currentResX = currentDisplay.resolutionx;
currentDisplay.currentResY = currentDisplay.resolutiony;
}
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('pixeldepth') !== -1) currentDisplay.pixeldepth = parseInt(parts[1]); // in BIT
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('framebufferdepth') !== -1) currentDisplay.pixeldepth = parseInt(parts[1]); // in BIT
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('maindisplay') !== -1 && parts[1].replace(/ +/g, '').toLowerCase() === 'yes') currentDisplay.main = true;
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('built-in') !== -1 && parts[1].replace(/ +/g, '').toLowerCase() === 'yes') {
currentDisplay.builtin = true;
currentDisplay.connection = '';
}
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('connectiontype') !== -1) {
currentDisplay.builtin = false;
currentDisplay.connection = parts[1].trim();
}
}
}
}
if (Object.keys(currentController).length > 0) {// just changed to Displays
controllers.push(currentController);
}
if (Object.keys(currentDisplay).length > 0) {// just changed to Displays
displays.push(currentDisplay);
}
return ({
controllers: controllers,
displays: displays
});
}
function parseLinesLinuxControllers(lines) {
let controllers = [];
let currentController = {
vendor: '',
model: '',
bus: '',
vram: -1,
vramDynamic: false
};
let isGraphicsController = false;
// PCI bus IDs
let pciIDs = [];
try {
pciIDs = execSync('export LC_ALL=C; dmidecode -t 9 2>/dev/null; unset LC_ALL | grep "Bus Address: "').toString().split('\n');
for (let i = 0; i < pciIDs.length; i++) {
pciIDs[i] = pciIDs[i].replace('Bus Address:', '').replace('0000:', '').trim();
}
pciIDs = pciIDs.filter(function (el) {
return el != null && el;
});
} catch (e) {
util.noop();
}
for (let i = 0; i < lines.length; i++) {
if ('' !== lines[i].trim()) {
if (' ' !== lines[i][0] && '\t' !== lines[i][0]) { // first line of new entry
let isExternal = (pciIDs.indexOf(lines[i].split(' ')[0]) >= 0);
let vgapos = lines[i].toLowerCase().indexOf(' vga ');
let _3dcontrollerpos = lines[i].toLowerCase().indexOf('3d controller');
if (vgapos !== -1 || _3dcontrollerpos !== -1) { // VGA
if (_3dcontrollerpos !== -1 && vgapos === -1) {
vgapos = _3dcontrollerpos;
}
if (currentController.vendor || currentController.model || currentController.bus || currentController.vram !== -1 || currentController.vramDynamic) { // already a controller found
controllers.push(currentController);
currentController = {
vendor: '',
model: '',
bus: '',
vram: -1,
vramDynamic: false
};
}
isGraphicsController = true;
let endpos = lines[i].search(/\[[0-9a-f]{4}:[0-9a-f]{4}]|$/);
let parts = lines[i].substr(vgapos, endpos - vgapos).split(':');
if (parts.length > 1) {
parts[1] = parts[1].trim();
if (parts[1].toLowerCase().indexOf('corporation') >= 0) {
currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf('corporation') + 11).trim();
currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf('corporation') + 11, 200).trim().split('(')[0];
currentController.bus = (pciIDs.length > 0 && isExternal) ? 'PCIe' : 'Onboard';
currentController.vram = -1;
currentController.vramDynamic = false;
} else if (parts[1].toLowerCase().indexOf(' inc.') >= 0) {
if ((parts[1].match(new RegExp(']', 'g')) || []).length > 1) {
currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(']') + 1).trim();
currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf(']') + 1, 200).trim().split('(')[0].trim();
} else {
currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(' inc.') + 5).trim();
currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf(' inc.') + 5, 200).trim().split('(')[0].trim();
}
currentController.bus = (pciIDs.length > 0 && isExternal) ? 'PCIe' : 'Onboard';
currentController.vram = -1;
currentController.vramDynamic = false;
} else if (parts[1].toLowerCase().indexOf(' ltd.') >= 0) {
if ((parts[1].match(new RegExp(']', 'g')) || []).length > 1) {
currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(']') + 1).trim();
currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf(']') + 1, 200).trim().split('(')[0].trim();
} else {
currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(' ltd.') + 5).trim();
currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf(' ltd.') + 5, 200).trim().split('(')[0].trim();
}
}
}
} else {
isGraphicsController = false;
}
}
if (isGraphicsController) { // within VGA details
let parts = lines[i].split(':');
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('devicename') !== -1 && parts[1].toLowerCase().indexOf('onboard') !== -1) currentController.bus = 'Onboard';
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('region') !== -1 && parts[1].toLowerCase().indexOf('memory') !== -1) {
let memparts = parts[1].split('=');
if (memparts.length > 1) {
currentController.vram = parseInt(memparts[1]);
}
}
}
}
}
if (currentController.vendor || currentController.model || currentController.bus || currentController.vram !== -1 || currentController.vramDynamic) { // already a controller found
controllers.push(currentController);
}
return (controllers);
}
function parseLinesLinuxEdid(edid) {
// parsen EDID
// --> model
// --> resolutionx
// --> resolutiony
// --> builtin = false
// --> pixeldepth (?)
// --> sizex
// --> sizey
let result = {
vendor: '',
model: '',
main: false,
builtin: false,
connection: '',
sizex: -1,
sizey: -1,
pixeldepth: -1,
resolutionx: -1,
resolutiony: -1,
currentResX: -1,
currentResY: -1,
positionX: 0,
positionY: 0,
currentRefreshRate: -1
};
// find first "Detailed Timing Description"
let start = 108;
if (edid.substr(start, 6) === '000000') {
start += 36;
}
if (edid.substr(start, 6) === '000000') {
start += 36;
}
if (edid.substr(start, 6) === '000000') {
start += 36;
}
if (edid.substr(start, 6) === '000000') {
start += 36;
}
result.resolutionx = parseInt('0x0' + edid.substr(start + 8, 1) + edid.substr(start + 4, 2));
result.resolutiony = parseInt('0x0' + edid.substr(start + 14, 1) + edid.substr(start + 10, 2));
result.sizex = parseInt('0x0' + edid.substr(start + 28, 1) + edid.substr(start + 24, 2));
result.sizey = parseInt('0x0' + edid.substr(start + 29, 1) + edid.substr(start + 26, 2));
// monitor name
start = edid.indexOf('000000fc00'); // find first "Monitor Description Data"
if (start >= 0) {
let model_raw = edid.substr(start + 10, 26);
if (model_raw.indexOf('0a') !== -1) {
model_raw = model_raw.substr(0, model_raw.indexOf('0a'));
}
try {
if (model_raw.length > 2) {
result.model = model_raw.match(/.{1,2}/g).map(function (v) {
return String.fromCharCode(parseInt(v, 16));
}).join('');
}
} catch (e) {
util.noop();
}
} else {
result.model = '';
}
return result;
}
function parseLinesLinuxDisplays(lines, depth) {
let displays = [];
let currentDisplay = {
vendor: '',
model: '',
main: false,
builtin: false,
connection: '',
sizex: -1,
sizey: -1,
pixeldepth: -1,
resolutionx: -1,
resolutiony: -1,
currentResX: -1,
currentResY: -1,
positionX: 0,
positionY: 0,
currentRefreshRate: -1
};
let is_edid = false;
let is_current = false;
let edid_raw = '';
let start = 0;
for (let i = 1; i < lines.length; i++) { // start with second line
if ('' !== lines[i].trim()) {
if (' ' !== lines[i][0] && '\t' !== lines[i][0] && lines[i].toLowerCase().indexOf(' connected ') !== -1) { // first line of new entry
if (currentDisplay.model || currentDisplay.main || currentDisplay.builtin || currentDisplay.connection || currentDisplay.sizex !== -1 || currentDisplay.pixeldepth !== -1 || currentDisplay.resolutionx !== -1) { // push last display to array
displays.push(currentDisplay);
currentDisplay = {
vendor: '',
model: '',
main: false,
builtin: false,
connection: '',
sizex: -1,
sizey: -1,
pixeldepth: -1,
resolutionx: -1,
resolutiony: -1,
currentResX: -1,
currentResY: -1,
positionX: 0,
positionY: 0,
currentRefreshRate: -1
};
}
let parts = lines[i].split(' ');
currentDisplay.connection = parts[0];
currentDisplay.main = lines[i].toLowerCase().indexOf(' primary ') >= 0;
currentDisplay.builtin = (parts[0].toLowerCase().indexOf('edp') >= 0);
}
// try to read EDID information
if (is_edid) {
if (lines[i].search(/\S|$/) > start) {
edid_raw += lines[i].toLowerCase().trim();
} else {
// parsen EDID
let edid_decoded = parseLinesLinuxEdid(edid_raw);
currentDisplay.vendor = edid_decoded.vendor;
currentDisplay.model = edid_decoded.model;
currentDisplay.resolutionx = edid_decoded.resolutionx;
currentDisplay.resolutiony = edid_decoded.resolutiony;
currentDisplay.sizex = edid_decoded.sizex;
currentDisplay.sizey = edid_decoded.sizey;
currentDisplay.pixeldepth = depth;
is_edid = false;
}
}
if (lines[i].toLowerCase().indexOf('edid:') >= 0) {
is_edid = true;
start = lines[i].search(/\S|$/);
}
if (lines[i].toLowerCase().indexOf('*current') >= 0) {
const parts1 = lines[i].split('(');
if (parts1 && parts1.length > 1 && parts1[0].indexOf('x') >= 0) {
const resParts = parts1[0].trim().split('x');
currentDisplay.currentResX = util.toInt(resParts[0]);
currentDisplay.currentResY = util.toInt(resParts[1]);
}
is_current = true;
}
if (is_current && lines[i].toLowerCase().indexOf('clock') >= 0 && lines[i].toLowerCase().indexOf('hz') >= 0 && lines[i].toLowerCase().indexOf('v: height') >= 0) {
const parts1 = lines[i].split('clock');
if (parts1 && parts1.length > 1 && parts1[1].toLowerCase().indexOf('hz') >= 0) {
currentDisplay.currentRefreshRate = util.toInt(parts1[1]);
}
is_current = false;
}
}
}
// pushen displays
if (currentDisplay.model || currentDisplay.main || currentDisplay.builtin || currentDisplay.connection || currentDisplay.sizex !== -1 || currentDisplay.pixeldepth !== -1 || currentDisplay.resolutionx !== -1) { // still information there
displays.push(currentDisplay);
}
return displays;
}
// function starts here
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
controllers: [],
displays: []
};
if (_darwin) {
let cmd = 'system_profiler SPDisplaysDataType';
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result = parseLinesDarwin(lines);
}
if (callback) {
callback(result);
}
resolve(result);
});
}
if (_linux) {
// Raspberry: https://elinux.org/RPI_vcgencmd_usage
if (util.isRaspberry() && util.isRaspbian()) {
let cmd = 'fbset -s | grep \'mode "\'; vcgencmd get_mem gpu; tvservice -s; tvservice -n;';
exec(cmd, function (error, stdout) {
let lines = stdout.toString().split('\n');
if (lines.length > 3 && lines[0].indexOf('mode "') >= -1 && lines[2].indexOf('0x12000a') > -1) {
const parts = lines[0].replace('mode', '').replace(/"/g, '').trim().split('x');
if (parts.length === 2) {
result.displays.push({
vendor: '',
model: util.getValue(lines, 'device_name', '='),
main: true,
builtin: false,
connection: 'HDMI',
sizex: -1,
sizey: -1,
pixeldepth: -1,
resolutionx: parseInt(parts[0], 10),
resolutiony: parseInt(parts[1], 10),
currentResX: -1,
currentResY: -1,
positionX: 0,
positionY: 0,
currentRefreshRate: -1
});
}
}
if (lines.length > 1 && lines[1].indexOf('gpu=') >= -1) {
result.controllers.push({
vendor: 'Broadcom',
model: 'VideoCore IV',
bus: '',
vram: lines[1].replace('gpu=', ''),
vramDynamic: true
});
}
if (callback) {
callback(result);
}
resolve(result);
});
} else {
let cmd = 'lspci -vvv 2>/dev/null';
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result.controllers = parseLinesLinuxControllers(lines);
}
let cmd = 'xdpyinfo 2>/dev/null | grep \'depth of root window\' | awk \'{ print $5 }\'';
exec(cmd, function (error, stdout) {
let depth = 0;
if (!error) {
let lines = stdout.toString().split('\n');
depth = parseInt(lines[0]) || 0;
}
let cmd = 'xrandr --verbose 2>/dev/null';
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result.displays = parseLinesLinuxDisplays(lines, depth);
}
if (callback) {
callback(result);
}
resolve(result);
});
});
});
}
}
if (_freebsd || _openbsd || _netbsd) {
if (callback) { callback(result); }
resolve(result);
}
if (_sunos) {
if (callback) { callback(result); }
resolve(result);
}
if (_windows) {
// https://blogs.technet.microsoft.com/heyscriptingguy/2013/10/03/use-powershell-to-discover-multi-monitor-information/
// https://devblogs.microsoft.com/scripting/use-powershell-to-discover-multi-monitor-information/
try {
const workload = [];
workload.push(util.wmic('path win32_VideoController get /value'));
workload.push(util.wmic('path win32_desktopmonitor get /value'));
workload.push(util.powerShell('Get-CimInstance -Namespace root\\wmi -ClassName WmiMonitorBasicDisplayParams | fl'));
workload.push(util.powerShell('Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Screen]::AllScreens'));
workload.push(util.powerShell('Get-CimInstance -Namespace root\\wmi -ClassName WmiMonitorConnectionParams | fl'));
Promise.all(
workload
).then(data => {
// controller
let csections = data[0].split(/\n\s*\n/);
result.controllers = parseLinesWindowsControllers(csections);
// displays
let dsections = data[1].split(/\n\s*\n/);
// result.displays = parseLinesWindowsDisplays(dsections);
dsections.shift();
dsections.pop();
// monitor (powershell)
let msections = data[2].split('Active ');
msections.shift();
// forms.screens (powershell)
let ssections = data[3].split('BitsPerPixel ');
ssections.shift();
// connection params (powershell) - video type
let tsections = data[4].split(/\n\s*\n/);
tsections.shift();
result.displays = parseLinesWindowsDisplaysPowershell(ssections, msections, dsections, tsections);
if (result.controllers.length === 1 && result.displays.length === 1) {
if (_resolutionx) {
result.displays[0].currentResX = _resolutionx;
if (!result.displays[0].resolutionx) {
result.displays[0].resolutionx = _resolutionx;
}
}
if (_resolutiony) {
result.displays[0].currentResY = _resolutiony;
if (result.displays[0].resolutiony === 0) {
result.displays[0].resolutiony = _resolutiony;
}
}
if (_pixeldepth) {
result.displays[0].pixeldepth = _pixeldepth;
}
if (_refreshrate && !result.displays[0].refreshrate) {
result.displays[0].currentRefreshRate = _refreshrate;
}
}
if (callback) {
callback(result);
}
resolve(result);
})
.catch(() => {
if (callback) {
callback(result);
}
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
function parseLinesWindowsControllers(sections) {
let controllers = [];
for (let i in sections) {
if (sections.hasOwnProperty(i)) {
if (sections[i].trim() !== '') {
let lines = sections[i].trim().split('\r\n');
controllers.push({
vendor: util.getValue(lines, 'AdapterCompatibility', '='),
model: util.getValue(lines, 'name', '='),
bus: util.getValue(lines, 'PNPDeviceID', '=').startsWith('PCI') ? 'PCI' : '',
vram: parseInt(util.getValue(lines, 'AdapterRAM', '='), 10) / 1024 / 1024,
vramDynamic: (util.getValue(lines, 'VideoMemoryType', '=') === '2')
});
_resolutionx = util.toInt(util.getValue(lines, 'CurrentHorizontalResolution', '='));
_resolutiony = util.toInt(util.getValue(lines, 'CurrentVerticalResolution', '='));
_refreshrate = util.toInt(util.getValue(lines, 'CurrentRefreshRate', '='));
_pixeldepth = util.toInt(util.getValue(lines, 'CurrentBitsPerPixel', '='));
}
}
}
return controllers;
}
// function parseLinesWindowsDisplays(sections) {
// let displays = [];
// for (let i in sections) {
// if (sections.hasOwnProperty(i)) {
// if (sections[i].trim() !== '') {
// let lines = sections[i].trim().split('\r\n');
// displays.push({
// vendor: util.getValue(lines, 'MonitorManufacturer', '='),
// model: util.getValue(lines, 'Name', '='),
// main: false,
// builtin: false,
// connection: '',
// sizex: -1,
// sizey: -1,
// pixeldepth: -1,
// resolutionx: util.toInt(util.getValue(lines, 'ScreenWidth', '=')),
// resolutiony: util.toInt(util.getValue(lines, 'ScreenHeight', '=')),
// });
// }
// }
// }
// return displays;
// }
function parseLinesWindowsDisplaysPowershell(ssections, msections, dsections, tsections) {
let displays = [];
let vendor = '';
let model = '';
let deviceID = '';
if (dsections && dsections.length) {
let linesDisplay = dsections[0].split(os.EOL);
vendor = util.getValue(linesDisplay, 'MonitorManufacturer', '=');
model = util.getValue(linesDisplay, 'Name', '=');
deviceID = util.getValue(linesDisplay, 'PNPDeviceID', '=').replace(/&amp;/g, '&').toLowerCase();
}
for (let i = 0; i < ssections.length; i++) {
if (ssections[i].trim() !== '') {
ssections[i] = 'BitsPerPixel ' + ssections[i];
msections[i] = 'Active ' + msections[i];
let linesScreen = ssections[i].split(os.EOL);
let linesMonitor = msections[i].split(os.EOL);
let linesConnection = tsections[i].split(os.EOL);
const bitsPerPixel = util.getValue(linesScreen, 'BitsPerPixel');
const bounds = util.getValue(linesScreen, 'Bounds').replace('{', '').replace('}', '').split(',');
const primary = util.getValue(linesScreen, 'Primary');
const sizex = util.getValue(linesMonitor, 'MaxHorizontalImageSize');
const sizey = util.getValue(linesMonitor, 'MaxVerticalImageSize');
const instanceName = util.getValue(linesMonitor, 'InstanceName').toLowerCase();
const videoOutputTechnology = util.getValue(linesConnection, 'VideoOutputTechnology');
displays.push({
vendor: instanceName.startsWith(deviceID) ? vendor : '',
model: instanceName.startsWith(deviceID) ? model : '',
main: primary.toLowerCase() === 'true',
builtin: videoOutputTechnology === '2147483648',
connection: videoOutputTechnology && videoTypes[videoOutputTechnology] ? videoTypes[videoOutputTechnology] : '',
resolutionx: util.toInt(util.getValue(bounds, 'Width', '=')),
resolutiony: util.toInt(util.getValue(bounds, 'Height', '=')),
sizex: sizex ? parseInt(sizex, 10) : -1,
sizey: sizey ? parseInt(sizey, 10) : -1,
pixeldepth: bitsPerPixel,
currentResX: util.toInt(util.getValue(bounds, 'Width', '=')),
currentResY: util.toInt(util.getValue(bounds, 'Height', '=')),
positionX: util.toInt(util.getValue(bounds, 'X', '=')),
positionY: util.toInt(util.getValue(bounds, 'Y', '=')),
});
}
}
return displays;
}
}
exports.graphics = graphics;
// Type definitions for systeminformation
// Project: https://github.com/sebhildebrandt/systeminformation
// Definitions by: sebhildebrandt <https://github.com/sebhildebrandt>
export namespace Systeminformation {
// 1. General
interface TimeData {
current: string;
uptime: string;
timezone: string;
timezoneName: string;
}
// 2. System (HW)
interface SystemData {
manufacturer: string;
model: string;
version: string;
serial: string;
uuid: string;
sku: string;
}
interface BiosData {
vendor: string;
version: string;
releaseDate: string;
revision: string;
}
interface BaseboardData {
manufacturer: string;
model: string;
version: string;
serial: string;
assetTag: string;
}
interface ChassisData {
manufacturer: string;
model: string;
type: string;
version: string;
serial: string;
assetTag: string;
sku: string;
}
// 3. CPU, Memory, Disks, Battery, Graphics
interface CpuData {
manufacturer: string;
brand: string;
vendor: string;
family: string;
model: string;
stepping: string;
revision: string;
voltage: string;
speed: string;
speedmin: string;
speedmax: string;
cores: number;
physicalCores: number;
processors: number;
socket: string;
cache: CpuCacheData;
}
interface CpuWithFlagsData extends CpuData {
flags: string;
}
interface CpuCacheData {
l1d: number;
l1i: number;
l2: number;
l3: number;
}
interface CpuCurrentSpeedData {
min: string;
max: string;
avg: string;
cores: number[];
}
interface CpuTemperatureData {
main: number;
cores: number[];
max: number;
}
interface MemData {
total: number;
free: number;
used: number;
active: number;
available: number;
buffcache: number;
swaptotal: number;
swapused: number;
swapfree: number;
}
interface MemLayoutData {
size: number;
bank: string;
type: string;
clockSpeed: number;
formFactor: string;
partNum: string;
serialNum: string;
voltageConfigured: number;
voltageMin: number;
voltageMax: number;
}
interface DiskLayoutData {
device: string;
type: string;
name: string;
vendor: string;
size: number;
bytesPerSector: number;
totalCylinders: number;
totalHeads: number;
totalSectors: number;
totalTracks: number;
tracksPerCylinder: number;
sectorsPerTrack: number;
firmwareRevision: string;
serialNum: string;
interfaceType: string;
smartStatus: string;
}
interface BatteryData {
hasbattery: boolean;
cyclecount: number;
ischarging: boolean;
maxcapacity: number;
currentcapacity: number;
percent: number;
timeremaining: number,
acconnected: boolean;
type: string;
model: string;
manufacturer: string;
serial: string;
}
interface GraphicsData {
controllers: GraphicsControllerData[];
displays: GraphicsDisplayData[];
}
interface GraphicsControllerData {
vendor: string;
model: string;
bus: string;
vram: number;
vramDynamic: boolean;
}
interface GraphicsDisplayData {
vendor: string;
model: string;
main: boolean;
builtin: boolean;
connection: string;
sizex: number;
sizey: number;
pixeldepth: number;
resolutionx: number;
resolutiony: number;
currentResX: number;
currentResY: number;
positionX: number;
positionY: number;
currentRefreshRate: number;
}
// 4. Operating System
interface OsData {
platform: string;
distro: string;
release: string;
codename: string;
kernel: string;
arch: string;
hostname: string;
codepage: string;
logofile: string;
serial: string;
build: string;
servicepack: string;
}
interface UuidData {
os: string;
}
interface VersionData {
kernel: string;
openssl: string;
systemOpenssl: string;
systemOpensslLib: string;
node: string;
v8: string;
npm: string;
yarn: string;
pm2: string;
gulp: string;
grunt: string;
git: string;
tsc: string;
mysql: string;
redis: string;
mongodb: string;
nginx: string;
php: string;
docker: string;
postfix: string;
postgresql: string;
perl: string;
python: string;
python3: string;
pip: string;
pip3: string;
java: string;
gcc: string;
virtualbox: string;
}
interface UserData {
user: string;
tty: string;
date: string;
time: string;
ip: string;
command: string;
}
// 5. File System
interface FsSizeData {
fs: string;
type: string;
size: number;
used: number;
use: number;
mount: string;
}
interface FsOpenFilesData {
max: number;
allocated: number;
available: number;
}
interface BlockDevicesData {
name: string;
identifier: string;
type: string;
fstype: string;
mount: string;
size: number;
physical: string;
uuid: string;
label: string;
model: string;
serial: string;
removable: boolean;
protocol: string;
}
interface FsStatsData {
rx_bytes: number;
wx_bytes: number;
tx_bytes: number;
rx_sec: number;
wx_sec: number;
tx_sec: number;
ms: number;
}
interface DisksIoData {
rIO: number;
wIO: number;
tIO: number;
rIO_sec: number;
wIO_sec: number;
tIO_sec: number;
ms: number;
}
// 6. Network related functions
interface NetworkInterfacesData {
iface: string;
ifaceName: string;
ip4: string;
ip6: string;
mac: string;
internal: boolean;
virtual: boolean;
operstate: string;
type: string;
duplex: string;
mtu: number;
speed: number;
carrier_changes: number;
}
interface NetworkStatsData {
iface: string;
operstate: string;
rx_bytes: number;
rx_dropped: number;
rx_errors: number;
tx_bytes: number;
tx_dropped: number;
tx_errors: number;
rx_sec: number;
tx_sec: number;
ms: number;
}
interface NetworkConnectionsData {
protocol: string;
localaddress: string;
localport: string;
peeraddress: string;
peerport: string;
state: string;
pid: number;
process: string;
}
interface InetChecksiteData {
url: string;
ok: boolean;
status: number;
ms: number;
}
interface WifiNetworkData {
ssid: string;
bssid: string;
mode: string;
channel: number;
frequency: number;
signalLevel: number;
quality: number;
security: string[];
wpaFlags: string[];
rsnFlags: string[];
}
// 7. Current Load, Processes & Services
interface CurrentLoadData {
avgload: number;
currentload: number;
currentload_user: number;
currentload_system: number;
currentload_nice: number;
currentload_idle: number;
currentload_irq: number;
raw_currentload: number;
raw_currentload_user: number;
raw_currentload_system: number;
raw_currentload_nice: number;
raw_currentload_idle: number;
raw_currentload_irq: number;
cpus: CurrentLoadCpuData[];
}
interface CurrentLoadCpuData {
load: number;
load_user: number;
load_system: number;
load_nice: number;
load_idle: number;
load_irq: number;
raw_load: number;
raw_load_user: number;
raw_load_system: number;
raw_load_nice: number;
raw_load_idle: number;
raw_load_irq: number;
}
interface ProcessesData {
all: number;
running: number;
blocked: number;
sleeping: number;
unknown: number;
list: ProcessesProcessData[];
}
interface ProcessesProcessData {
pid: number;
parentPid: number;
name: string,
pcpu: number;
pcpuu: number;
pcpus: number;
pmem: number;
priority: number;
mem_vsz: number;
mem_rss: number;
nice: number;
started: string,
state: string;
tty: string;
user: string;
command: string;
params: string;
path: string;
}
interface ProcessesProcessLoadData {
proc: string;
pid: number;
pids: number[];
cpu: number;
mem: number;
}
interface ServicesData {
name: string;
running: boolean;
startmode: string;
pids: number[];
pcpu: number;
pmem: number;
}
// 8. Docker
interface DockerInfoData {
id: string;
containers: number;
containersRunning: number;
containersPaused: number;
containersStopped: number;
images: number;
driver: string;
memoryLimit: boolean;
swapLimit: boolean;
kernelMemory: boolean;
cpuCfsPeriod: boolean;
cpuCfsQuota: boolean;
cpuShares: boolean;
cpuSet: boolean;
ipv4Forwarding: boolean;
bridgeNfIptables: boolean;
bridgeNfIp6tables: boolean;
debug: boolean;
mfd: number;
oomKillDisable: boolean;
ngoroutines: number;
systemTime: string;
loggingDriver: string;
cgroupDriver: string;
nEventsListener: number;
kernelVersion: string;
operatingSystem: string;
osType: string;
architecture: string;
ncpu: number;
memTotal: number;
dockerRootDir: string;
httpProxy: string;
httpsProxy: string;
noProxy: string;
name: string;
labels: string[];
experimentalBuild: boolean;
serverVersion: string;
clusterStore: string;
clusterAdvertise: string;
defaultRuntime: string;
liveRestoreEnabled: boolean;
isolation: string;
initBinary: string;
productLicense: string;
}
interface DockerContainerData {
id: string;
name: string;
image: string;
imageID: string;
command: string;
created: number;
started: number;
finished: number;
createdAt: string;
startedAt: string;
finishedAt: string;
state: string;
restartCount: number;
platform: string;
driver: string;
ports: number[];
mounts: DockerContainerMountData[];
}
interface DockerContainerMountData {
Type: string;
Source: string;
Destination: string;
Mode: string;
RW: boolean;
Propagation: string;
}
interface DockerContainerStatsData {
id: string;
mem_usage: number;
mem_limit: number;
mem_percent: number;
cpu_percent: number;
netIO: {
rx: number;
wx: number;
};
blockIO: {
r: number;
w: number;
};
restartCount: number;
cpu_stats: any;
precpu_stats: any;
memory_stats: any,
networks: any;
}
// 9. Virtual Box
interface VboxInfoData {
id: string;
name: string;
running: boolean;
started: string;
runningSince: number;
stopped: string;
stoppedSince: number;
guestOS: string;
hardwareUUID: string;
memory: number;
vram: number;
cpus: number;
cpuExepCap: string;
cpuProfile: string;
chipset: string;
firmware: string;
pageFusion: boolean;
configFile: string;
snapshotFolder: string;
logFolder: string;
HPET: boolean;
PAE: boolean;
longMode: boolean;
tripleFaultReset: boolean;
APIC: boolean;
X2APIC: boolean;
ACPI: boolean;
IOAPIC: boolean;
biosAPICmode: string;
bootMenuMode: string;
bootDevice1: string;
bootDevice2: string;
bootDevice3: string;
bootDevice4: string;
timeOffset: string;
RTC: string;
}
// 10. "Get All at once" - functions
interface StaticData {
version: string;
system: SystemData;
bios: BiosData;
baseboard: BaseboardData;
chassis: ChassisData;
os: OsData;
uuid: UuidData;
versions: VersionData;
cpu: CpuWithFlagsData;
graphics: GraphicsData;
net: NetworkInterfacesData[];
memLayout: MemLayoutData[];
diskLayout: DiskLayoutData[];
}
}
export function version(): string;
export function system(cb?: (data: Systeminformation.SystemData) => any): Promise<Systeminformation.SystemData>;
export function bios(cb?: (data: Systeminformation.BiosData) => any): Promise<Systeminformation.BiosData>;
export function baseboard(cb?: (data: Systeminformation.BaseboardData) => any): Promise<Systeminformation.BaseboardData>;
export function chassis(cb?: (data: Systeminformation.ChassisData) => any): Promise<Systeminformation.ChassisData>;
export function time(): Systeminformation.TimeData;
export function osInfo(cb?: (data: Systeminformation.OsData) => any): Promise<Systeminformation.OsData>;
export function versions(cb?: (data: Systeminformation.VersionData) => any): Promise<Systeminformation.VersionData>;
export function shell(cb?: (data: string) => any): Promise<string>;
export function uuid(cb?: (data: Systeminformation.UuidData) => any): Promise<Systeminformation.UuidData>;
export function cpu(cb?: (data: Systeminformation.CpuData) => any): Promise<Systeminformation.CpuData>;
export function cpuFlags(cb?: (data: string) => any): Promise<string>;
export function cpuCache(cb?: (data: Systeminformation.CpuCacheData) => any): Promise<Systeminformation.CpuCacheData>;
export function cpuCurrentspeed(cb?: (data: Systeminformation.CpuCurrentSpeedData) => any): Promise<Systeminformation.CpuCurrentSpeedData>;
export function cpuTemperature(cb?: (data: Systeminformation.CpuTemperatureData) => any): Promise<Systeminformation.CpuTemperatureData>;
export function currentLoad(cb?: (data: Systeminformation.CurrentLoadData) => any): Promise<Systeminformation.CurrentLoadData>;
export function fullLoad(cb?: (data: number) => any): Promise<number>;
export function mem(cb?: (data: Systeminformation.MemData) => any): Promise<Systeminformation.MemData>;
export function memLayout(cb?: (data: Systeminformation.MemLayoutData[]) => any): Promise<Systeminformation.MemLayoutData[]>;
export function battery(cb?: (data: Systeminformation.BatteryData) => any): Promise<Systeminformation.BatteryData>;
export function graphics(cb?: (data: Systeminformation.GraphicsData) => any): Promise<Systeminformation.GraphicsData>;
export function fsSize(cb?: (data: Systeminformation.FsSizeData[]) => any): Promise<Systeminformation.FsSizeData[]>;
export function fsOpenFiles(cb?: (data: Systeminformation.FsOpenFilesData[]) => any): Promise<Systeminformation.FsOpenFilesData[]>;
export function blockDevices(cb?: (data: Systeminformation.BlockDevicesData[]) => any): Promise<Systeminformation.BlockDevicesData[]>;
export function fsStats(cb?: (data: Systeminformation.FsStatsData) => any): Promise<Systeminformation.FsStatsData>;
export function disksIO(cb?: (data: Systeminformation.DisksIoData) => any): Promise<Systeminformation.DisksIoData>;
export function diskLayout(cb?: (data: Systeminformation.DiskLayoutData[]) => any): Promise<Systeminformation.DiskLayoutData[]>;
export function networkInterfaceDefault(cb?: (data: string) => any): Promise<string>;
export function networkInterfaces(cb?: (data: Systeminformation.NetworkInterfacesData[]) => any): Promise<Systeminformation.NetworkInterfacesData[]>;
export function networkStats(ifaces?: string, cb?: (data: Systeminformation.NetworkStatsData[]) => any): Promise<Systeminformation.NetworkStatsData[]>;
export function networkConnections(cb?: (data: Systeminformation.NetworkConnectionsData[]) => any): Promise<Systeminformation.NetworkConnectionsData[]>;
export function inetChecksite(url: string, cb?: (data: Systeminformation.InetChecksiteData) => any): Promise<Systeminformation.InetChecksiteData>;
export function inetLatency(host?: string, cb?: (data: number) => any): Promise<number>;
export function wifiNetworks(cb?: (data: Systeminformation.WifiNetworkData[]) => any): Promise<Systeminformation.WifiNetworkData[]>;
export function users(cb?: (data: Systeminformation.UserData[]) => any): Promise<Systeminformation.UserData[]>;
export function processes(cb?: (data: Systeminformation.ProcessesData) => any): Promise<Systeminformation.ProcessesData>;
export function processLoad(processName: string, cb?: (data: Systeminformation.ProcessesProcessLoadData) => any): Promise<Systeminformation.ProcessesProcessLoadData>;
export function services(serviceName: string, cb?: (data: Systeminformation.ServicesData[]) => any): Promise<Systeminformation.ServicesData[]>;
export function dockerInfo(cb?: (data: Systeminformation.DockerInfoData) => any): Promise<Systeminformation.DockerInfoData>;
export function dockerContainers(all?: boolean, cb?: (data: Systeminformation.DockerContainerData[]) => any): Promise<Systeminformation.DockerContainerData[]>;
export function dockerContainerStats(id?: string, cb?: (data: Systeminformation.DockerContainerStatsData[]) => any): Promise<Systeminformation.DockerContainerStatsData[]>;
export function dockerContainerProcesses(id?: string, cb?: (data: any) => any): Promise<any>;
export function dockerAll(cb?: (data: any) => any): Promise<any>;
export function vboxInfo(cb?: (data: Systeminformation.VboxInfoData[]) => any): Promise<Systeminformation.VboxInfoData[]>;
export function getStaticData(cb?: (data: Systeminformation.StaticData) => any): Promise<Systeminformation.StaticData>;
export function getDynamicData(srv?: string, iface?: string, cb?: (data: any) => any): Promise<any>;
export function getAllData(srv?: string, iface?: string, cb?: (data: any) => any): Promise<any>;
'use strict';
// @ts-check
// ==================================================================================
// index.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// Contributors: Guillaume Legrain (https://github.com/glegrain)
// Riccardo Novaglia (https://github.com/richy24)
// Quentin Busuttil (https://github.com/Buzut)
// Lapsio (https://github.com/lapsio)
// csy (https://github.com/csy1983)
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// ----------------------------------------------------------------------------------
// Dependencies
// ----------------------------------------------------------------------------------
const lib_version = require('../package.json').version;
const util = require('./util');
const system = require('./system');
const osInfo = require('./osinfo');
const cpu = require('./cpu');
const memory = require('./memory');
const battery = require('./battery');
const graphics = require('./graphics');
const filesystem = require('./filesystem');
const network = require('./network');
const wifi = require('./wifi');
const processes = require('./processes');
const users = require('./users');
const internet = require('./internet');
const docker = require('./docker');
const vbox = require('./virtualbox');
let _platform = process.platform;
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
// ----------------------------------------------------------------------------------
// init
// ----------------------------------------------------------------------------------
if (_windows) {
util.getCodepage();
}
// ----------------------------------------------------------------------------------
// General
// ----------------------------------------------------------------------------------
function version() {
return lib_version;
}
// ----------------------------------------------------------------------------------
// Get static and dynamic data (all)
// ----------------------------------------------------------------------------------
// --------------------------
// get static data - they should not change until restarted
function getStaticData(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let data = {};
data.version = version();
Promise.all([
system.system(),
system.bios(),
system.baseboard(),
system.chassis(),
osInfo.osInfo(),
osInfo.uuid(),
osInfo.versions(),
cpu.cpu(),
cpu.cpuFlags(),
graphics.graphics(),
network.networkInterfaces(),
memory.memLayout(),
filesystem.diskLayout()
]).then(res => {
data.system = res[0];
data.bios = res[1];
data.baseboard = res[2];
data.chassis = res[3];
data.os = res[4];
data.uuid = res[5];
data.versions = res[6];
data.cpu = res[7];
data.cpu.flags = res[8];
data.graphics = res[9];
data.net = res[10];
data.memLayout = res[11];
data.diskLayout = res[12];
if (callback) { callback(data); }
resolve(data);
});
});
});
}
// --------------------------
// get all dynamic data - e.g. for monitoring agents
// may take some seconds to get all data
// --------------------------
// 2 additional parameters needed
// - srv: comma separated list of services to monitor e.g. "mysql, apache, postgresql"
// - iface: define network interface for which you like to monitor network speed e.g. "eth0"
function getDynamicData(srv, iface, callback) {
if (util.isFunction(iface)) {
callback = iface;
iface = '';
}
if (util.isFunction(srv)) {
callback = srv;
srv = '';
}
return new Promise((resolve) => {
process.nextTick(() => {
iface = iface || network.getDefaultNetworkInterface();
srv = srv || '';
// use closure to track ƒ completion
let functionProcessed = (function () {
let totalFunctions = 14;
if (_windows) totalFunctions = 10;
if (_freebsd || _openbsd || _netbsd) totalFunctions = 11;
if (_sunos) totalFunctions = 6;
return function () {
if (--totalFunctions === 0) {
if (callback) {
callback(data);
}
resolve(data);
}
};
})();
// var totalFunctions = 14;
// function functionProcessed() {
// if (--totalFunctions === 0) {
// if (callback) { callback(data) }
// resolve(data);
// }
// }
let data = {};
// get time
data.time = osInfo.time();
/**
* @namespace
* @property {Object} versions
* @property {string} versions.node
* @property {string} versions.v8
*/
data.node = process.versions.node;
data.v8 = process.versions.v8;
cpu.cpuCurrentspeed().then(res => {
data.cpuCurrentspeed = res;
functionProcessed();
});
users.users().then(res => {
data.users = res;
functionProcessed();
});
if (!_windows) {
processes.processes().then(res => {
data.processes = res;
functionProcessed();
});
}
cpu.currentLoad().then(res => {
data.currentLoad = res;
functionProcessed();
});
if (!_sunos) {
cpu.cpuTemperature().then(res => {
data.temp = res;
functionProcessed();
});
}
if (!_openbsd && !_freebsd && !_netbsd && !_sunos) {
network.networkStats(iface).then(res => {
data.networkStats = res;
functionProcessed();
});
}
if (!_sunos) {
network.networkConnections().then(res => {
data.networkConnections = res;
functionProcessed();
});
}
memory.mem().then(res => {
data.mem = res;
functionProcessed();
});
if (!_sunos) {
battery().then(res => {
data.battery = res;
functionProcessed();
});
}
if (!_windows && !_sunos) {
processes.services(srv).then(res => {
data.services = res;
functionProcessed();
});
}
if (!_sunos) {
filesystem.fsSize().then(res => {
data.fsSize = res;
functionProcessed();
});
}
if (!_windows && !_openbsd && !_freebsd && !_netbsd && !_sunos) {
filesystem.fsStats().then(res => {
data.fsStats = res;
functionProcessed();
});
}
if (!_windows && !_openbsd && !_freebsd && !_netbsd && !_sunos) {
filesystem.disksIO().then(res => {
data.disksIO = res;
functionProcessed();
});
}
internet.inetLatency().then(res => {
data.inetLatency = res;
functionProcessed();
});
});
});
}
// --------------------------
// get all data at once
// --------------------------
// 2 additional parameters needed
// - srv: comma separated list of services to monitor e.g. "mysql, apache, postgresql"
// - iface: define network interface for which you like to monitor network speed e.g. "eth0"
function getAllData(srv, iface, callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let data = {};
if (iface && util.isFunction(iface) && !callback) {
callback = iface;
iface = '';
}
if (srv && util.isFunction(srv) && !iface && !callback) {
callback = srv;
srv = '';
iface = '';
}
getStaticData().then(res => {
data = res;
getDynamicData(srv, iface).then(res => {
for (let key in res) {
if (res.hasOwnProperty(key)) {
data[key] = res[key];
}
}
if (callback) { callback(data); }
resolve(data);
});
});
});
});
}
// ----------------------------------------------------------------------------------
// export all libs
// ----------------------------------------------------------------------------------
exports.version = version;
exports.system = system.system;
exports.bios = system.bios;
exports.baseboard = system.baseboard;
exports.chassis = system.chassis;
exports.time = osInfo.time;
exports.osInfo = osInfo.osInfo;
exports.versions = osInfo.versions;
exports.shell = osInfo.shell;
exports.uuid = osInfo.uuid;
exports.cpu = cpu.cpu;
exports.cpuFlags = cpu.cpuFlags;
exports.cpuCache = cpu.cpuCache;
exports.cpuCurrentspeed = cpu.cpuCurrentspeed;
exports.cpuTemperature = cpu.cpuTemperature;
exports.currentLoad = cpu.currentLoad;
exports.fullLoad = cpu.fullLoad;
exports.mem = memory.mem;
exports.memLayout = memory.memLayout;
exports.battery = battery;
exports.graphics = graphics.graphics;
exports.fsSize = filesystem.fsSize;
exports.fsOpenFiles = filesystem.fsOpenFiles;
exports.blockDevices = filesystem.blockDevices;
exports.fsStats = filesystem.fsStats;
exports.disksIO = filesystem.disksIO;
exports.diskLayout = filesystem.diskLayout;
exports.networkInterfaceDefault = network.networkInterfaceDefault;
exports.networkInterfaces = network.networkInterfaces;
exports.networkStats = network.networkStats;
exports.networkConnections = network.networkConnections;
exports.wifiNetworks = wifi.wifiNetworks;
exports.services = processes.services;
exports.processes = processes.processes;
exports.processLoad = processes.processLoad;
exports.users = users.users;
exports.inetChecksite = internet.inetChecksite;
exports.inetLatency = internet.inetLatency;
exports.dockerInfo = docker.dockerInfo;
exports.dockerContainers = docker.dockerContainers;
exports.dockerContainerStats = docker.dockerContainerStats;
exports.dockerContainerProcesses = docker.dockerContainerProcesses;
exports.dockerAll = docker.dockerAll;
exports.vboxInfo = vbox.vboxInfo;
exports.getStaticData = getStaticData;
exports.getDynamicData = getDynamicData;
exports.getAllData = getAllData;
'use strict';
// @ts-check
// ==================================================================================
// internet.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 12. Internet
// ----------------------------------------------------------------------------------
const exec = require('child_process').exec;
const util = require('./util');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
// --------------------------
// check if external site is available
function inetChecksite(url, callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
url: url,
ok: false,
status: 404,
ms: -1
};
if (url) {
url = url.toLowerCase();
let t = Date.now();
if (_linux || _freebsd || _openbsd || _netbsd || _darwin || _sunos) {
let args = ' -I --connect-timeout 5 -m 5 ' + url + ' 2>/dev/null | head -n 1 | cut -d " " -f2';
let cmd = 'curl';
exec(cmd + args, function (error, stdout) {
let statusCode = parseInt(stdout.toString());
result.status = statusCode || 404;
result.ok = !error && (statusCode === 200 || statusCode === 301 || statusCode === 302 || statusCode === 304);
result.ms = (result.ok ? Date.now() - t : -1);
if (callback) { callback(result); }
resolve(result);
});
}
if (_windows) { // if this is stable, this can be used for all OS types
const http = (url.startsWith('https:') ? require('https') : require('http'));
try {
http.get(url, (res) => {
const statusCode = res.statusCode;
result.status = statusCode || 404;
result.ok = (statusCode === 200 || statusCode === 301 || statusCode === 302 || statusCode === 304);
if (statusCode !== 200) {
res.resume();
result.ms = (result.ok ? Date.now() - t : -1);
if (callback) { callback(result); }
resolve(result);
} else {
res.on('data', () => { });
res.on('end', () => {
result.ms = (result.ok ? Date.now() - t : -1);
if (callback) { callback(result); }
resolve(result);
});
}
}).on('error', () => {
if (callback) { callback(result); }
resolve(result);
});
} catch (err) {
if (callback) { callback(result); }
resolve(result);
}
}
} else {
if (callback) { callback(result); }
resolve(result);
}
});
});
}
exports.inetChecksite = inetChecksite;
// --------------------------
// check inet latency
function inetLatency(host, callback) {
// fallback - if only callback is given
if (util.isFunction(host) && !callback) {
callback = host;
host = '';
}
host = host || '8.8.8.8';
return new Promise((resolve) => {
process.nextTick(() => {
let cmd;
if (_linux || _freebsd || _openbsd || _netbsd || _darwin) {
if (_linux) {
cmd = 'ping -c 2 -w 3 ' + host + ' | grep rtt';
}
if (_freebsd || _openbsd || _netbsd) {
cmd = 'ping -c 2 -t 3 ' + host + ' | grep round-trip';
}
if (_darwin) {
cmd = 'ping -c 2 -t 3 ' + host + ' | grep avg';
}
exec(cmd, function (error, stdout) {
let result = -1;
if (!error) {
const line = stdout.toString().split('=');
if (line.length > 1) {
const parts = line[1].split('/');
if (parts.length > 1) {
result = parseFloat(parts[1]);
}
}
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_sunos) {
exec('ping -s -a ' + host + ' 56 2 | grep avg', { timeout: 3000 }, function (error, stdout) {
let result = -1;
if (!error) {
const line = stdout.toString().split('=');
if (line.length > 1) {
const parts = line[1].split('/');
if (parts.length > 1) {
result = parseFloat(parts[1].replace(',', '.'));
}
}
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_windows) {
let result = -1;
try {
exec('ping ' + host + ' -n 1', util.execOptsWin, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\r\n');
lines.shift();
lines.forEach(function (line) {
if ((line.toLowerCase().match(/ms/g) || []).length === 3) {
let l = line.replace(/ +/g, ' ').split(' ');
if (l.length > 6) {
result = parseFloat(l[l.length - 1]);
}
}
});
}
if (callback) { callback(result); }
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.inetLatency = inetLatency;
'use strict';
// @ts-check
// ==================================================================================
// memory.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 5. Memory
// ----------------------------------------------------------------------------------
const os = require('os');
const exec = require('child_process').exec;
const util = require('./util');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
const OSX_RAM_manufacturers = {
'0x014F': 'Transcend Information',
'0x2C00': 'Micron Technology Inc.',
'0x802C': 'Micron Technology Inc.',
'0x80AD': 'Hynix Semiconductor Inc.',
'0x80CE': 'Samsung Electronics Inc.',
'0xAD00': 'Hynix Semiconductor Inc.',
'0xCE00': 'Samsung Electronics Inc.',
'0x02FE': 'Elpida',
'0x5105': 'Qimonda AG i. In.',
'0x8551': 'Qimonda AG i. In.',
'0x859B': 'Crucial'
};
// _______________________________________________________________________________________
// | R A M | H D |
// |______________________|_________________________| | |
// | active buffers/cache | | |
// |________________________________________________|___________|_________|______________|
// | used free | used free |
// |____________________________________________________________|________________________|
// | total | swap |
// |____________________________________________________________|________________________|
// free (older versions)
// ----------------------------------
// # free
// total used free shared buffers cached
// Mem: 16038 (1) 15653 (2) 384 (3) 0 (4) 236 (5) 14788 (6)
// -/+ buffers/cache: 628 (7) 15409 (8)
// Swap: 16371 83 16288
//
// |------------------------------------------------------------|
// | R A M |
// |______________________|_____________________________________|
// | active (2-(5+6) = 7) | available (3+5+6 = 8) |
// |______________________|_________________________|___________|
// | active | buffers/cache (5+6) | |
// |________________________________________________|___________|
// | used (2) | free (3) |
// |____________________________________________________________|
// | total (1) |
// |____________________________________________________________|
//
// free (since free von procps-ng 3.3.10)
// ----------------------------------
// # free
// total used free shared buffers/cache available
// Mem: 16038 (1) 628 (2) 386 (3) 0 (4) 15024 (5) 14788 (6)
// Swap: 16371 83 16288
//
// |------------------------------------------------------------|
// | R A M |
// |______________________|_____________________________________|
// | | available (6) estimated |
// |______________________|_________________________|___________|
// | active (2) | buffers/cache (5) | free (3) |
// |________________________________________________|___________|
// | total (1) |
// |____________________________________________________________|
//
// Reference: http://www.software-architect.net/blog/article/date/2015/06/12/-826c6e5052.html
// /procs/meminfo - sample (all in kB)
//
// MemTotal: 32806380 kB
// MemFree: 19220948 kB
// MemAvailable: 20851100 kB
// Buffers: 532892 kB
// Cached: 1935000 kB
// SwapCached: 0 kB
// Active: 11953672 kB
// Inactive: 1069288 kB
// SwapTotal: 16768892 kB
// SwapFree: 16768892 kB
function mem(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
total: os.totalmem(),
free: os.freemem(),
used: os.totalmem() - os.freemem(),
active: os.totalmem() - os.freemem(), // temporarily (fallback)
available: os.freemem(), // temporarily (fallback)
buffcache: 0,
swaptotal: 0,
swapused: 0,
swapfree: 0
};
if (_linux) {
exec('export LC_ALL=C; cat /proc/meminfo ; unset LC_ALL', function (error, stdout) {
if (!error) {
const lines = stdout.toString().split('\n');
result.total = parseInt(util.getValue(lines, 'memtotal'), 10);
result.total = result.total ? result.total * 1024 : os.totalmem();
result.free = parseInt(util.getValue(lines, 'memfree'), 10);
result.free = result.free ? result.free * 1024 : os.freemem();
result.used = result.total - result.free;
let buffers = parseInt(util.getValue(lines, 'buffers'), 10);
buffers = buffers ? buffers * 1024 : 0;
let cached = parseInt(util.getValue(lines, 'cached'), 10);
cached = cached ? cached * 1024 : 0;
result.buffcache = buffers + cached;
result.available = parseInt(util.getValue(lines, 'memavailable'), 10);
result.available = result.available ? result.available * 1024 : os.freemem();
// result.active = result.total - result.free - result.buffcache;
result.active = parseInt(util.getValue(lines, 'active'), 10);
result.active = result.active ? result.active * 1024 : 0;
result.buffcache = result.total - result.free - result.active;
result.swaptotal = parseInt(util.getValue(lines, 'swaptotal'), 10);
result.swaptotal = result.swaptotal ? result.swaptotal * 1024 : 0;
result.swapfree = parseInt(util.getValue(lines, 'swapfree'), 10);
result.swapfree = result.swapfree ? result.swapfree * 1024 : 0;
result.swapused = result.swaptotal - result.swapfree;
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_freebsd || _openbsd || _netbsd) {
exec('/sbin/sysctl -a | grep -E "hw.realmem|hw.physmem|vm.stats.vm.v_page_count|vm.stats.vm.v_wire_count|vm.stats.vm.v_active_count|vm.stats.vm.v_inactive_count|vm.stats.vm.v_cache_count|vm.stats.vm.v_free_count|vm.stats.vm.v_page_size"', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
const pagesize = parseInt(util.getValue(lines, 'vm.stats.vm.v_page_size'), 10);
const inactive = parseInt(util.getValue(lines, 'vm.stats.vm.v_inactive_count'), 10) * pagesize;
const cache = parseInt(util.getValue(lines, 'vm.stats.vm.v_cache_count'), 10) * pagesize;
result.total = parseInt(util.getValue(lines, 'hw.realmem'), 10);
if (isNaN(result.total)) result.total = parseInt(util.getValue(lines, 'hw.physmem'), 10);
result.free = parseInt(util.getValue(lines, 'vm.stats.vm.v_free_count'), 10) * pagesize;
result.buffcache = inactive + cache;
result.available = result.buffcache + result.free;
result.active = result.total - result.free - result.buffcache;
result.swaptotal = 0;
result.swapfree = 0;
result.swapused = 0;
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_sunos) {
if (callback) { callback(result); }
resolve(result);
}
if (_darwin) {
exec('vm_stat | grep "Pages active"', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result.active = parseInt(lines[0].split(':')[1], 10) * 4096;
result.buffcache = result.used - result.active;
result.available = result.free + result.buffcache;
}
exec('sysctl -n vm.swapusage', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
if (lines.length > 0) {
let line = lines[0].replace(/,/g, '.').replace(/M/g, '');
line = line.trim().split(' ');
for (let i = 0; i < line.length; i++) {
if (line[i].toLowerCase().indexOf('total') !== -1) result.swaptotal = parseFloat(line[i].split('=')[1].trim()) * 1024 * 1024;
if (line[i].toLowerCase().indexOf('used') !== -1) result.swapused = parseFloat(line[i].split('=')[1].trim()) * 1024 * 1024;
if (line[i].toLowerCase().indexOf('free') !== -1) result.swapfree = parseFloat(line[i].split('=')[1].trim()) * 1024 * 1024;
}
}
}
if (callback) { callback(result); }
resolve(result);
});
});
}
if (_windows) {
let swaptotal = 0;
let swapused = 0;
try {
util.wmic('pagefile get AllocatedBaseSize, CurrentUsage').then((stdout, error) => {
if (!error) {
let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0);
lines.forEach(function (line) {
if (line !== '') {
line = line.trim().split(/\s\s+/);
swaptotal = swaptotal + parseInt(line[0], 10);
swapused = swapused + parseInt(line[1], 10);
}
});
}
result.swaptotal = swaptotal * 1024 * 1024;
result.swapused = swapused * 1024 * 1024;
result.swapfree = result.swaptotal - result.swapused;
if (callback) { callback(result); }
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.mem = mem;
function memLayout(callback) {
function getManufacturer(manId) {
if (OSX_RAM_manufacturers.hasOwnProperty(manId)) {
return (OSX_RAM_manufacturers[manId]);
}
return manId;
}
return new Promise((resolve) => {
process.nextTick(() => {
let result = [];
if (_linux || _freebsd || _openbsd || _netbsd) {
exec('export LC_ALL=C; dmidecode -t memory 2>/dev/null | grep -iE "Size:|Type|Speed|Manufacturer|Form Factor|Locator|Memory Device|Serial Number|Voltage|Part Number"; unset LC_ALL', function (error, stdout) {
if (!error) {
let devices = stdout.toString().split('Memory Device');
devices.shift();
devices.forEach(function (device) {
let lines = device.split('\n');
if (parseInt(util.getValue(lines, 'Size'), 10) > 0) {
result.push({
size: parseInt(util.getValue(lines, 'Size'), 10) * 1024 * 1024,
bank: util.getValue(lines, 'Bank Locator'),
type: util.getValue(lines, 'Type:'),
clockSpeed: (util.getValue(lines, 'Configured Clock Speed:') ? parseInt(util.getValue(lines, 'Configured Clock Speed:'), 10) : (util.getValue(lines, 'Speed:') ? parseInt(util.getValue(lines, 'Speed:'), 10) : -1)),
formFactor: util.getValue(lines, 'Form Factor:'),
manufacturer: util.getValue(lines, 'Manufacturer:'),
partNum: util.getValue(lines, 'Part Number:'),
serialNum: util.getValue(lines, 'Serial Number:'),
voltageConfigured: parseFloat(util.getValue(lines, 'Configured Voltage:') || -1),
voltageMin: parseFloat(util.getValue(lines, 'Minimum Voltage:') || -1),
voltageMax: parseFloat(util.getValue(lines, 'Maximum Voltage:') || -1),
});
} else {
result.push({
size: 0,
bank: util.getValue(lines, 'Bank Locator'),
type: 'Empty',
clockSpeed: 0,
formFactor: util.getValue(lines, 'Form Factor:'),
partNum: '',
serialNum: '',
voltageConfigured: -1,
voltageMin: -1,
voltageMax: -1,
});
}
});
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_darwin) {
exec('system_profiler SPMemoryDataType', function (error, stdout) {
if (!error) {
let devices = stdout.toString().split(' BANK ');
let hasBank = true;
if (devices.length === 1) {
devices = stdout.toString().split(' DIMM');
hasBank = false;
}
devices.shift();
devices.forEach(function (device) {
let lines = device.split('\n');
const bank = (hasBank ? 'BANK ' : 'DIMM') + lines[0].trim();
const size = parseInt(util.getValue(lines, ' Size'));
if (size) {
result.push({
size: size * 1024 * 1024 * 1024,
bank: bank,
type: util.getValue(lines, ' Type:'),
clockSpeed: parseInt(util.getValue(lines, ' Speed:'), 10),
formFactor: '',
manufacturer: getManufacturer(util.getValue(lines, ' Manufacturer:')),
partNum: util.getValue(lines, ' Part Number:'),
serialNum: util.getValue(lines, ' Serial Number:'),
voltageConfigured: -1,
voltageMin: -1,
voltageMax: -1,
});
} else {
result.push({
size: 0,
bank: bank,
type: 'Empty',
clockSpeed: 0,
formFactor: '',
manufacturer: '',
partNum: '',
serialNum: '',
voltageConfigured: -1,
voltageMin: -1,
voltageMax: -1,
});
}
});
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_sunos) {
if (callback) { callback(result); }
resolve(result);
}
if (_windows) {
const memoryTypes = 'Unknown|Other|DRAM|Synchronous DRAM|Cache DRAM|EDO|EDRAM|VRAM|SRAM|RAM|ROM|FLASH|EEPROM|FEPROM|EPROM|CDRAM|3DRAM|SDRAM|SGRAM|RDRAM|DDR|DDR2|DDR2 FB-DIMM|Reserved|DDR3|FBD2|DDR4|LPDDR|LPDDR2|LPDDR3|LPDDR4'.split('|');
const FormFactors = 'Unknown|Other|SIP|DIP|ZIP|SOJ|Proprietary|SIMM|DIMM|TSOP|PGA|RIMM|SODIMM|SRIMM|SMD|SSMP|QFP|TQFP|SOIC|LCC|PLCC|BGA|FPBGA|LGA'.split('|');
try {
util.wmic('memorychip get /value').then((stdout, error) => {
if (!error) {
let devices = stdout.toString().split('BankL');
devices.shift();
devices.forEach(function (device) {
let lines = device.split('\r\n');
result.push({
size: parseInt(util.getValue(lines, 'Capacity', '='), 10) || 0,
bank: util.getValue(lines, 'abel', '='), // BankLabel
type: memoryTypes[parseInt(util.getValue(lines, 'MemoryType', '='), 10)],
clockSpeed: parseInt(util.getValue(lines, 'ConfiguredClockSpeed', '='), 10) || 0,
formFactor: FormFactors[parseInt(util.getValue(lines, 'FormFactor', '='), 10) || 0],
manufacturer: util.getValue(lines, 'Manufacturer', '='),
partNum: util.getValue(lines, 'PartNumber', '='),
serialNum: util.getValue(lines, 'SerialNumber', '='),
voltageConfigured: (parseInt(util.getValue(lines, 'ConfiguredVoltage', '='), 10) || 0) / 1000.0,
voltageMin: (parseInt(util.getValue(lines, 'MinVoltage', '='), 10) || 0) / 1000.0,
voltageMax: (parseInt(util.getValue(lines, 'MaxVoltage', '='), 10) || 0) / 1000.0,
});
});
}
if (callback) { callback(result); }
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.memLayout = memLayout;
'use strict';
// @ts-check
// ==================================================================================
// network.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 9. Network
// ----------------------------------------------------------------------------------
const os = require('os');
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;
const fs = require('fs');
const util = require('./util');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
let _network = {};
let _default_iface = '';
let _ifaces = [];
let _networkInterfaces = [];
let _mac = {};
let pathToIp;
function getDefaultNetworkInterface() {
let ifaces = os.networkInterfaces();
let ifacename = '';
let ifacenameFirst = '';
let scopeid = 9999;
// fallback - "first" external interface (sorted by scopeid)
for (let dev in ifaces) {
if (ifaces.hasOwnProperty(dev)) {
ifaces[dev].forEach(function (details) {
if (details && details.internal === false) {
ifacenameFirst = ifacenameFirst || dev; // fallback if no scopeid
if (details.scopeid && details.scopeid < scopeid) {
ifacename = dev;
scopeid = details.scopeid;
}
}
});
}
}
ifacename = ifacename || ifacenameFirst || '';
if (_windows) {
// https://www.inetdaemon.com/tutorials/internet/ip/routing/default_route.shtml
const cmd = 'netstat -r';
const result = execSync(cmd);
const lines = result.toString().split(os.EOL);
let defaultIp = '';
lines.forEach(line => {
line = line.replace(/\s+/g, ' ').trim();
if (line.indexOf('0.0.0.0 0.0.0.0') > -1 && !(/[a-zA-Z]/.test(line))) {
const parts = line.split(' ');
if (parts.length >= 5) {
defaultIp = parts[parts.length - 2];
}
}
});
if (defaultIp) {
for (let dev in ifaces) {
if (ifaces.hasOwnProperty(dev)) {
ifaces[dev].forEach(function (details) {
if (details && details.address && details.address === defaultIp) {
ifacename = dev;
}
});
}
}
}
}
if (_linux || _darwin || _freebsd || _openbsd || _netbsd || _sunos) {
let cmd = '';
if (_linux) cmd = 'ip route 2> /dev/null | grep default | awk \'{print $5}\'';
if (_darwin) cmd = 'route get 0.0.0.0 2>/dev/null | grep interface: | awk \'{print $2}\'';
if (_freebsd || _openbsd || _netbsd || _sunos) cmd = 'route get 0.0.0.0 | grep interface:';
let result = execSync(cmd);
ifacename = result.toString().split('\n')[0];
if (ifacename.indexOf(':') > -1) {
ifacename = ifacename.split(':')[1].trim();
}
}
if (ifacename) _default_iface = ifacename;
return _default_iface;
}
exports.getDefaultNetworkInterface = getDefaultNetworkInterface;
function getMacAddresses() {
let iface = '';
let mac = '';
let result = {};
if (_linux || _freebsd || _openbsd || _netbsd) {
if (typeof pathToIp === 'undefined') {
try {
const lines = execSync('which ip').toString().split('\n');
if (lines.length && lines[0].indexOf(':') === -1 && lines[0].indexOf('/') === 0) {
pathToIp = lines[0];
} else {
pathToIp = '';
}
} catch (e) {
pathToIp = '';
}
}
const cmd = 'export LC_ALL=C; ' + ((pathToIp) ? pathToIp + ' link show up' : '/sbin/ifconfig') + '; unset LC_ALL';
let res = execSync(cmd);
const lines = res.toString().split('\n');
for (let i = 0; i < lines.length; i++) {
if (lines[i] && lines[i][0] !== ' ') {
if (pathToIp) {
let nextline = lines[i + 1].trim().split(' ');
if (nextline[0] === 'link/ether') {
iface = lines[i].split(' ')[1];
iface = iface.slice(0, iface.length - 1);
mac = nextline[1];
}
} else {
iface = lines[i].split(' ')[0];
mac = lines[i].split('HWaddr ')[1];
}
if (iface && mac) {
result[iface] = mac.trim();
iface = '';
mac = '';
}
}
}
}
if (_darwin) {
const cmd = '/sbin/ifconfig';
let res = execSync(cmd);
const lines = res.toString().split('\n');
for (let i = 0; i < lines.length; i++) {
if (lines[i] && lines[i][0] !== '\t' && lines[i].indexOf(':') > 0) {
iface = lines[i].split(':')[0];
} else if (lines[i].indexOf('\tether ') === 0) {
mac = lines[i].split('\tether ')[1];
if (iface && mac) {
result[iface] = mac.trim();
iface = '';
mac = '';
}
}
}
}
return result;
}
function networkInterfaceDefault(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = getDefaultNetworkInterface();
if (callback) { callback(result); }
resolve(result);
});
});
}
exports.networkInterfaceDefault = networkInterfaceDefault;
// --------------------------
// NET - interfaces
function parseLinesWindowsNics(sections) {
let nics = [];
for (let i in sections) {
if (sections.hasOwnProperty(i)) {
if (sections[i].trim() !== '') {
let lines = sections[i].trim().split('\r\n');
let netEnabled = util.getValue(lines, 'NetEnabled', '=');
if (netEnabled) {
const speed = parseInt(util.getValue(lines, 'speed', '=').trim(), 10) / 1000000;
nics.push({
mac: util.getValue(lines, 'MACAddress', '=').toLowerCase(),
name: util.getValue(lines, 'Name', '=').replace(/\]/g, ')').replace(/\[/g, '('),
netEnabled: netEnabled === 'TRUE',
speed: isNaN(speed) ? -1 : speed,
operstate: util.getValue(lines, 'NetConnectionStatus', '=') === '2' ? 'up' : 'down',
type: util.getValue(lines, 'AdapterTypeID', '=') === '9' ? 'wireless' : 'wired'
});
}
}
}
}
return nics;
}
function getWindowsNics() {
const cmd = util.getWmic() + ' nic get MACAddress, name, NetEnabled, Speed, NetConnectionStatus, AdapterTypeId /value';
try {
const nsections = execSync(cmd, util.execOptsWin).split(/\n\s*\n/);
return (parseLinesWindowsNics(nsections));
} catch (e) {
return [];
}
}
function splitSectionsNics(lines) {
const result = [];
let section = [];
lines.forEach(function (line) {
if (!line.startsWith('\t')) {
if (section.length) {
result.push(section);
section = [];
}
}
section.push(line);
});
if (section.length) {
result.push(section);
}
return result;
}
function parseLinesDarwinNics(sections) {
let nics = [];
sections.forEach(section => {
let nic = {
iface: '',
mtu: -1,
mac: '',
ip6: '',
ip4: '',
speed: -1,
type: '',
operstate: '',
duplex: '',
internal: false
};
const first = section[0];
nic.iface = first.split(':')[0].trim();
let parts = first.split('> mtu');
nic.mtu = parts.length > 1 ? parseInt(parts[1], 10) : -1;
if (isNaN(nic.mtu)) {
nic.mtu = -1;
}
nic.internal = parts[0].indexOf('LOOPBACK') > -1;
section.forEach(line => {
if (line.trim().startsWith('ether ')) {
nic.mac = line.split('ether ')[1].toLowerCase().trim();
}
if (line.trim().startsWith('inet6 ') && !nic.ip6) {
nic.ip6 = line.split('inet6 ')[1].toLowerCase().split('%')[0].split(' ')[0];
}
if (line.trim().startsWith('inet ') && !nic.ip4) {
nic.ip4 = line.split('inet ')[1].toLowerCase().split(' ')[0];
}
});
let speed = util.getValue(section, 'link rate');
nic.speed = speed ? parseFloat(speed) : -1;
if (nic.speed === -1) {
speed = util.getValue(section, 'uplink rate');
nic.speed = speed ? parseFloat(speed) : -1;
if (nic.speed > -1 && speed.toLowerCase().indexOf('gbps') >= 0) {
nic.speed = nic.speed * 1000;
}
} else {
if (speed.toLowerCase().indexOf('gbps') >= 0) {
nic.speed = nic.speed * 1000;
}
}
nic.type = util.getValue(section, 'type').toLowerCase().indexOf('wi-fi') > -1 ? 'wireless' : 'wired';
nic.operstate = util.getValue(section, 'status').toLowerCase().indexOf('active') > -1 ? 'up' : 'down';
nic.duplex = util.getValue(section, 'media').toLowerCase().indexOf('half-duplex') > -1 ? 'half' : 'full';
if (nic.ip6 || nic.ip4 || nic.mac) {
nics.push(nic);
}
});
return nics;
}
function getDarwinNics() {
const cmd = 'ifconfig -v';
try {
const lines = execSync(cmd, util.execOptsWin).toString().split('\n');
const nsections = splitSectionsNics(lines);
return (parseLinesDarwinNics(nsections));
} catch (e) {
return [];
}
}
function testVirtualNic(iface, ifaceName, mac) {
const virtualMacs = ['00:00:00:00:00:00', '00:03:FF', '00:05:69', '00:0C:29', '00:0F:4B', '00:0F:4B', '00:13:07', '00:13:BE', '00:15:5d', '00:16:3E', '00:1C:42', '00:21:F6', '00:21:F6', '00:24:0B', '00:24:0B', '00:50:56', '00:A0:B1', '00:E0:C8', '08:00:27', '0A:00:27', '18:92:2C', '16:DF:49', '3C:F3:92', '54:52:00', 'FC:15:97'];
if (mac) {
return virtualMacs.filter(item => { return mac.toUpperCase().toUpperCase().startsWith(item.substr(0, mac.length)); }).length > 0 ||
iface.toLowerCase().indexOf(' virtual ') > -1 ||
ifaceName.toLowerCase().indexOf(' virtual ') > -1 ||
iface.toLowerCase().indexOf('vethernet ') > -1 ||
ifaceName.toLowerCase().indexOf('vethernet ') > -1 ||
iface.toLowerCase().startsWith('veth') ||
ifaceName.toLowerCase().startsWith('veth') ||
iface.toLowerCase().startsWith('vboxnet') ||
ifaceName.toLowerCase().startsWith('vboxnet');
} else return false;
}
function networkInterfaces(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let ifaces = os.networkInterfaces();
let result = [];
let nics = [];
// seperate handling in OSX
if (_darwin || _freebsd || _openbsd || _netbsd) {
nics = getDarwinNics();
// console.log(nics);
// console.log('-------');
// console.log(ifaces);
nics.forEach(nic => {
result.push({
iface: nic.iface,
ifaceName: nic.iface,
ip4: nic.ip4,
ip6: nic.ip6,
mac: nic.mac,
internal: nic.internal,
virtual: nic.internal ? false : testVirtualNic(nic.iface, nic.iface, nic.mac),
operstate: nic.operstate,
type: nic.type,
duplex: nic.duplex,
mtu: nic.mtu,
speed: nic.speed,
carrierChanges: 0
});
});
if (callback) { callback(result); }
resolve(result);
} else {
if (JSON.stringify(ifaces) === JSON.stringify(_ifaces)) {
// no changes - just return object
result = _networkInterfaces;
if (callback) { callback(result); }
resolve(result);
} else {
_ifaces = ifaces;
if (_windows) {
nics = getWindowsNics();
}
for (let dev in ifaces) {
let ip4 = '';
let ip6 = '';
let mac = '';
let duplex = '';
let mtu = '';
let speed = -1;
let carrierChanges = 0;
let operstate = 'down';
let type = '';
if (ifaces.hasOwnProperty(dev)) {
let ifaceName = dev;
ifaces[dev].forEach(function (details) {
if (details.family === 'IPv4') {
ip4 = details.address;
}
if (details.family === 'IPv6') {
if (!ip6 || ip6.match(/^fe80::/i)) {
ip6 = details.address;
}
}
mac = details.mac;
// fallback due to https://github.com/nodejs/node/issues/13581 (node 8.1 - node 8.2)
if (mac.indexOf('00:00:0') > -1 && (_linux || _darwin)) {
if (Object.keys(_mac).length === 0) {
_mac = getMacAddresses();
}
mac = _mac[dev] || '';
}
});
if (_linux) {
let iface = dev.split(':')[0].trim().toLowerCase();
const cmd = `echo -n "addr_assign_type: "; cat /sys/class/net/${iface}/addr_assign_type 2>/dev/null; echo;
echo -n "address: "; cat /sys/class/net/${iface}/address 2>/dev/null; echo;
echo -n "addr_len: "; cat /sys/class/net/${iface}/addr_len 2>/dev/null; echo;
echo -n "broadcast: "; cat /sys/class/net/${iface}/broadcast 2>/dev/null; echo;
echo -n "carrier: "; cat /sys/class/net/${iface}/carrier 2>/dev/null; echo;
echo -n "carrier_changes: "; cat /sys/class/net/${iface}/carrier_changes 2>/dev/null; echo;
echo -n "dev_id: "; cat /sys/class/net/${iface}/dev_id 2>/dev/null; echo;
echo -n "dev_port: "; cat /sys/class/net/${iface}/dev_port 2>/dev/null; echo;
echo -n "dormant: "; cat /sys/class/net/${iface}/dormant 2>/dev/null; echo;
echo -n "duplex: "; cat /sys/class/net/${iface}/duplex 2>/dev/null; echo;
echo -n "flags: "; cat /sys/class/net/${iface}/flags 2>/dev/null; echo;
echo -n "gro_flush_timeout: "; cat /sys/class/net/${iface}/gro_flush_timeout 2>/dev/null; echo;
echo -n "ifalias: "; cat /sys/class/net/${iface}/ifalias 2>/dev/null; echo;
echo -n "ifindex: "; cat /sys/class/net/${iface}/ifindex 2>/dev/null; echo;
echo -n "iflink: "; cat /sys/class/net/${iface}/iflink 2>/dev/null; echo;
echo -n "link_mode: "; cat /sys/class/net/${iface}/link_mode 2>/dev/null; echo;
echo -n "mtu: "; cat /sys/class/net/${iface}/mtu 2>/dev/null; echo;
echo -n "netdev_group: "; cat /sys/class/net/${iface}/netdev_group 2>/dev/null; echo;
echo -n "operstate: "; cat /sys/class/net/${iface}/operstate 2>/dev/null; echo;
echo -n "proto_down: "; cat /sys/class/net/${iface}/proto_down 2>/dev/null; echo;
echo -n "speed: "; cat /sys/class/net/${iface}/speed 2>/dev/null; echo;
echo -n "tx_queue_len: "; cat /sys/class/net/${iface}/tx_queue_len 2>/dev/null; echo;
echo -n "type: "; cat /sys/class/net/${iface}/type 2>/dev/null; echo;
echo -n "wireless: "; cat /proc/net/wireless 2>/dev/null \| grep ${iface}; echo
echo -n "wirelessspeed: "; iw dev ${iface} link 2>&1 \| grep bitrate; echo;`;
let lines = [];
try {
lines = execSync(cmd).toString().split('\n');
} catch (e) {
util.noop();
}
duplex = util.getValue(lines, 'duplex');
duplex = duplex.startsWith('cat') ? '' : duplex;
mtu = parseInt(util.getValue(lines, 'mtu'), 10);
let myspeed = parseInt(util.getValue(lines, 'speed'), 10);
speed = isNaN(myspeed) ? -1 : myspeed;
let wirelessspeed = util.getValue(lines, 'wirelessspeed').split('tx bitrate: ');
if (speed === -1 && wirelessspeed.length === 2) {
myspeed = parseFloat(wirelessspeed[1]);
speed = isNaN(myspeed) ? -1 : myspeed;
}
carrierChanges = parseInt(util.getValue(lines, 'carrier_changes'), 10);
operstate = util.getValue(lines, 'operstate');
type = operstate === 'up' ? (util.getValue(lines, 'wireless').trim() ? 'wireless' : 'wired') : 'unknown';
if (iface === 'lo' || iface.startsWith('bond')) { type = 'virtual'; }
}
if (_windows) {
nics.forEach(detail => {
if (detail.mac === mac) {
ifaceName = detail.name;
operstate = detail.operstate;
speed = detail.speed;
type = detail.type;
}
});
if (dev.toLowerCase().indexOf('wlan') >= 0 || ifaceName.toLowerCase().indexOf('wlan') >= 0 || ifaceName.toLowerCase().indexOf('wireless') >= 0) {
type = 'wireless';
}
}
let internal = (ifaces[dev] && ifaces[dev][0]) ? ifaces[dev][0].internal : null;
const virtual = internal ? false : testVirtualNic(dev, ifaceName, mac);
result.push({
iface: dev,
ifaceName,
ip4,
ip6,
mac,
internal,
virtual,
operstate,
type,
duplex,
mtu,
speed,
carrierChanges,
});
}
}
_networkInterfaces = result;
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.networkInterfaces = networkInterfaces;
// --------------------------
// NET - Speed
function calcNetworkSpeed(iface, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors) {
let result = {
iface,
operstate,
rx_bytes,
rx_dropped,
rx_errors,
tx_bytes,
tx_dropped,
tx_errors,
rx_sec: -1,
tx_sec: -1,
ms: 0
};
if (_network[iface] && _network[iface].ms) {
result.ms = Date.now() - _network[iface].ms;
result.rx_sec = (rx_bytes - _network[iface].rx_bytes) >= 0 ? (rx_bytes - _network[iface].rx_bytes) / (result.ms / 1000) : 0;
result.tx_sec = (tx_bytes - _network[iface].tx_bytes) >= 0 ? (tx_bytes - _network[iface].tx_bytes) / (result.ms / 1000) : 0;
_network[iface].rx_bytes = rx_bytes;
_network[iface].tx_bytes = tx_bytes;
_network[iface].rx_sec = result.rx_sec;
_network[iface].tx_sec = result.tx_sec;
_network[iface].ms = Date.now();
_network[iface].last_ms = result.ms;
_network[iface].operstate = operstate;
} else {
if (!_network[iface]) _network[iface] = {};
_network[iface].rx_bytes = rx_bytes;
_network[iface].tx_bytes = tx_bytes;
_network[iface].rx_sec = -1;
_network[iface].tx_sec = -1;
_network[iface].ms = Date.now();
_network[iface].last_ms = 0;
_network[iface].operstate = operstate;
}
return result;
}
function networkStats(ifaces, callback) {
let ifacesArray = [];
// fallback - if only callback is given
if (util.isFunction(ifaces) && !callback) {
callback = ifaces;
ifacesArray = [getDefaultNetworkInterface()];
} else {
ifaces = ifaces || getDefaultNetworkInterface();
ifaces = ifaces.trim().toLowerCase().replace(/,+/g, '|');
ifacesArray = ifaces.split('|');
}
return new Promise((resolve) => {
process.nextTick(() => {
const result = [];
const workload = [];
if (ifacesArray.length && ifacesArray[0].trim() === '*') {
ifacesArray = [];
networkInterfaces().then(allIFaces => {
for (let iface of allIFaces) {
ifacesArray.push(iface.iface);
}
networkStats(ifacesArray.join(',')).then(result => {
if (callback) { callback(result); }
resolve(result);
});
});
} else {
for (let iface of ifacesArray) {
workload.push(networkStatsSingle(iface.trim()));
}
if (workload.length) {
Promise.all(
workload
).then(data => {
if (callback) { callback(data); }
resolve(data);
});
} else {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
function networkStatsSingle(iface) {
function parseLinesWindowsPerfData(sections) {
let perfData = [];
for (let i in sections) {
if (sections.hasOwnProperty(i)) {
if (sections[i].trim() !== '') {
let lines = sections[i].trim().split('\r\n');
perfData.push({
name: util.getValue(lines, 'Name', '=').replace(/[()\[\] ]+/g, '').toLowerCase(),
rx_bytes: parseInt(util.getValue(lines, 'BytesReceivedPersec', '='), 10),
rx_errors: parseInt(util.getValue(lines, 'PacketsReceivedErrors', '='), 10),
rx_dropped: parseInt(util.getValue(lines, 'PacketsReceivedDiscarded', '='), 10),
tx_bytes: parseInt(util.getValue(lines, 'BytesSentPersec', '='), 10),
tx_errors: parseInt(util.getValue(lines, 'PacketsOutboundErrors', '='), 10),
tx_dropped: parseInt(util.getValue(lines, 'PacketsOutboundDiscarded', '='), 10)
});
}
}
}
return perfData;
}
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
iface: iface,
operstate: 'unknown',
rx_bytes: 0,
rx_dropped: 0,
rx_errors: 0,
tx_bytes: 0,
tx_dropped: 0,
tx_errors: 0,
rx_sec: -1,
tx_sec: -1,
ms: 0
};
let operstate = 'unknown';
let rx_bytes = 0;
let tx_bytes = 0;
let rx_dropped = 0;
let rx_errors = 0;
let tx_dropped = 0;
let tx_errors = 0;
let cmd, lines, stats;
if (!_network[iface] || (_network[iface] && !_network[iface].ms) || (_network[iface] && _network[iface].ms && Date.now() - _network[iface].ms >= 500)) {
if (_linux) {
if (fs.existsSync('/sys/class/net/' + iface)) {
cmd =
'cat /sys/class/net/' + iface + '/operstate; ' +
'cat /sys/class/net/' + iface + '/statistics/rx_bytes; ' +
'cat /sys/class/net/' + iface + '/statistics/tx_bytes; ' +
'cat /sys/class/net/' + iface + '/statistics/rx_dropped; ' +
'cat /sys/class/net/' + iface + '/statistics/rx_errors; ' +
'cat /sys/class/net/' + iface + '/statistics/rx_dropped; ' +
'cat /sys/class/net/' + iface + '/statistics/tx_errors; ';
exec(cmd, function (error, stdout) {
if (!error) {
lines = stdout.toString().split('\n');
operstate = lines[0].trim();
rx_bytes = parseInt(lines[1], 10);
tx_bytes = parseInt(lines[2], 10);
rx_dropped = parseInt(lines[3], 10);
rx_errors = parseInt(lines[4], 10);
tx_dropped = parseInt(lines[5], 10);
tx_errors = parseInt(lines[6], 10);
result = calcNetworkSpeed(iface, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors);
}
resolve(result);
});
} else {
resolve(result);
}
}
if (_freebsd || _openbsd || _netbsd) {
cmd = 'netstat -ibndI ' + iface;
exec(cmd, function (error, stdout) {
if (!error) {
lines = stdout.toString().split('\n');
for (let i = 1; i < lines.length; i++) {
const line = lines[i].replace(/ +/g, ' ').split(' ');
if (line && line[0] && line[7] && line[10]) {
rx_bytes = rx_bytes + parseInt(line[7]);
if (stats[6].trim() !== '-') { rx_dropped = rx_dropped + parseInt(stats[6]); }
if (stats[5].trim() !== '-') { rx_errors = rx_errors + parseInt(stats[5]); }
tx_bytes = tx_bytes + parseInt(line[10]);
if (stats[12].trim() !== '-') { tx_dropped = tx_dropped + parseInt(stats[12]); }
if (stats[9].trim() !== '-') { tx_errors = tx_errors + parseInt(stats[9]); }
operstate = 'up';
}
}
result = calcNetworkSpeed(iface, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors);
}
resolve(result);
});
}
if (_darwin) {
cmd = 'ifconfig ' + iface + ' | grep "status"';
exec(cmd, function (error, stdout) {
result.operstate = (stdout.toString().split(':')[1] || '').trim();
result.operstate = (result.operstate || '').toLowerCase();
result.operstate = (result.operstate === 'active' ? 'up' : (result.operstate === 'inactive' ? 'down' : 'unknown'));
cmd = 'netstat -bdI ' + iface;
exec(cmd, function (error, stdout) {
if (!error) {
lines = stdout.toString().split('\n');
// if there is less than 2 lines, no information for this interface was found
if (lines.length > 1 && lines[1].trim() !== '') {
// skip header line
// use the second line because it is tied to the NIC instead of the ipv4 or ipv6 address
stats = lines[1].replace(/ +/g, ' ').split(' ');
rx_bytes = parseInt(stats[6]);
rx_dropped = parseInt(stats[11]);
rx_errors = parseInt(stats[5]);
tx_bytes = parseInt(stats[9]);
tx_dropped = parseInt(stats[11]);
tx_errors = parseInt(stats[8]);
result = calcNetworkSpeed(iface, rx_bytes, tx_bytes, result.operstate, rx_dropped, rx_errors, tx_dropped, tx_errors);
}
}
resolve(result);
});
});
}
if (_windows) {
let perfData = [];
let ifaceName = iface;
// Performance Data
util.wmic('path Win32_PerfRawData_Tcpip_NetworkInterface Get name,BytesReceivedPersec,BytesSentPersec,BytesTotalPersec,PacketsOutboundDiscarded,PacketsOutboundErrors,PacketsReceivedDiscarded,PacketsReceivedErrors /value').then((stdout, error) => {
if (!error) {
const psections = stdout.toString().split(/\n\s*\n/);
perfData = parseLinesWindowsPerfData(psections);
}
// Network Interfaces
networkInterfaces().then(interfaces => {
// get bytes sent, received from perfData by name
rx_bytes = 0;
tx_bytes = 0;
perfData.forEach(detail => {
interfaces.forEach(det => {
if ((det.iface.toLowerCase() === iface.toLowerCase() ||
det.mac.toLowerCase() === iface.toLowerCase() ||
det.ip4.toLowerCase() === iface.toLowerCase() ||
det.ip6.toLowerCase() === iface.toLowerCase() ||
(det.ifaceName.replace(/[()\[\] ]+/g, '').toLowerCase() === iface.replace(/[()\[\] ]+/g, '').toLowerCase()) &&
det.ifaceName.replace(/[()\[\] ]+/g, '').toLowerCase() === detail.name)) {
ifaceName = det.iface;
rx_bytes = detail.rx_bytes;
rx_dropped = detail.rx_dropped;
rx_errors = detail.rx_errors;
tx_bytes = detail.tx_bytes;
tx_dropped = detail.tx_dropped;
tx_errors = detail.tx_errors;
operstate = det.operstate;
}
});
});
if (rx_bytes && tx_bytes) {
result = calcNetworkSpeed(ifaceName, parseInt(rx_bytes), parseInt(tx_bytes), operstate, rx_dropped, rx_errors, tx_dropped, tx_errors);
}
resolve(result);
});
});
}
} else {
result.rx_bytes = _network[iface].rx_bytes;
result.tx_bytes = _network[iface].tx_bytes;
result.rx_sec = _network[iface].rx_sec;
result.tx_sec = _network[iface].tx_sec;
result.ms = _network[iface].last_ms;
result.operstate = _network[iface].operstate;
resolve(result);
}
});
});
}
exports.networkStats = networkStats;
// --------------------------
// NET - connections (sockets)
function networkConnections(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = [];
if (_linux || _freebsd || _openbsd || _netbsd) {
let cmd = 'export LC_ALL=C; netstat -tunap | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"; unset LC_ALL';
if (_freebsd || _openbsd || _netbsd) cmd = 'export LC_ALL=C; netstat -na | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"; unset LC_ALL';
exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
line = line.replace(/ +/g, ' ').split(' ');
if (line.length >= 6) {
let localip = line[3];
let localport = '';
let localaddress = line[3].split(':');
if (localaddress.length > 1) {
localport = localaddress[localaddress.length - 1];
localaddress.pop();
localip = localaddress.join(':');
}
let peerip = line[4];
let peerport = '';
let peeraddress = line[4].split(':');
if (peeraddress.length > 1) {
peerport = peeraddress[peeraddress.length - 1];
peeraddress.pop();
peerip = peeraddress.join(':');
}
let connstate = line[5];
// if (connstate === 'VERBUNDEN') connstate = 'ESTABLISHED';
let proc = line[6].split('/');
if (connstate) {
result.push({
protocol: line[0],
localaddress: localip,
localport: localport,
peeraddress: peerip,
peerport: peerport,
state: connstate,
pid: proc[0] && proc[0] !== '-' ? parseInt(proc[0], 10) : -1,
process: proc[1] ? proc[1].split(' ')[0] : ''
});
}
}
});
if (callback) {
callback(result);
}
resolve(result);
} else {
cmd = 'ss -tunap | grep "ESTAB\\|SYN-SENT\\|SYN-RECV\\|FIN-WAIT1\\|FIN-WAIT2\\|TIME-WAIT\\|CLOSE\\|CLOSE-WAIT\\|LAST-ACK\\|LISTEN\\|CLOSING"';
exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
line = line.replace(/ +/g, ' ').split(' ');
if (line.length >= 6) {
let localip = line[4];
let localport = '';
let localaddress = line[4].split(':');
if (localaddress.length > 1) {
localport = localaddress[localaddress.length - 1];
localaddress.pop();
localip = localaddress.join(':');
}
let peerip = line[5];
let peerport = '';
let peeraddress = line[5].split(':');
if (peeraddress.length > 1) {
peerport = peeraddress[peeraddress.length - 1];
peeraddress.pop();
peerip = peeraddress.join(':');
}
let connstate = line[1];
if (connstate === 'ESTAB') connstate = 'ESTABLISHED';
if (connstate === 'TIME-WAIT') connstate = 'TIME_WAIT';
let pid = -1;
let process = '';
if (line.length >= 7 && line[6].indexOf('users:') > -1) {
let proc = line[6].replace('users:(("', '').replace(/"/g, '').split(',');
if (proc.length > 2) {
process = proc[0].split(' ')[0];
pid = parseInt(proc[1], 10);
}
}
if (connstate) {
result.push({
protocol: line[0],
localaddress: localip,
localport: localport,
peeraddress: peerip,
peerport: peerport,
state: connstate,
pid,
process
});
}
}
});
}
if (callback) {
callback(result);
}
resolve(result);
});
}
});
}
if (_darwin) {
let cmd = 'netstat -natv | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"';
exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
line = line.replace(/ +/g, ' ').split(' ');
if (line.length >= 8) {
let localip = line[3];
let localport = '';
let localaddress = line[3].split('.');
if (localaddress.length > 1) {
localport = localaddress[localaddress.length - 1];
localaddress.pop();
localip = localaddress.join('.');
}
let peerip = line[4];
let peerport = '';
let peeraddress = line[4].split('.');
if (peeraddress.length > 1) {
peerport = peeraddress[peeraddress.length - 1];
peeraddress.pop();
peerip = peeraddress.join('.');
}
let connstate = line[5];
let pid = parseInt(line[8], 10);
if (connstate) {
result.push({
protocol: line[0],
localaddress: localip,
localport: localport,
peeraddress: peerip,
peerport: peerport,
state: connstate,
pid: pid,
process: ''
});
}
}
});
if (callback) {
callback(result);
}
resolve(result);
}
});
}
if (_windows) {
let cmd = 'netstat -nao';
try {
exec(cmd, util.execOptsWin, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\r\n');
lines.forEach(function (line) {
line = line.trim().replace(/ +/g, ' ').split(' ');
if (line.length >= 4) {
let localip = line[1];
let localport = '';
let localaddress = line[1].split(':');
if (localaddress.length > 1) {
localport = localaddress[localaddress.length - 1];
localaddress.pop();
localip = localaddress.join(':');
}
let peerip = line[2];
let peerport = '';
let peeraddress = line[2].split(':');
if (peeraddress.length > 1) {
peerport = peeraddress[peeraddress.length - 1];
peeraddress.pop();
peerip = peeraddress.join(':');
}
let pid = line[4];
let connstate = line[3];
if (connstate === 'HERGESTELLT') connstate = 'ESTABLISHED';
if (connstate.startsWith('ABH')) connstate = 'LISTEN';
if (connstate === 'SCHLIESSEN_WARTEN') connstate = 'CLOSE_WAIT';
if (connstate === 'WARTEND') connstate = 'TIME_WAIT';
if (connstate === 'SYN_GESENDET') connstate = 'SYN_SENT';
if (connstate === 'LISTENING') connstate = 'LISTEN';
if (connstate === 'SYN_RECEIVED') connstate = 'SYN_RECV';
if (connstate === 'FIN_WAIT_1') connstate = 'FIN_WAIT1';
if (connstate === 'FIN_WAIT_2') connstate = 'FIN_WAIT2';
if (connstate) {
result.push({
protocol: line[0].toLowerCase(),
localaddress: localip,
localport: localport,
peeraddress: peerip,
peerport: peerport,
state: connstate,
pid,
process: ''
});
}
}
});
if (callback) {
callback(result);
}
resolve(result);
}
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.networkConnections = networkConnections;
'use strict';
// @ts-check
// ==================================================================================
// osinfo.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 3. Operating System
// ----------------------------------------------------------------------------------
const os = require('os');
const exec = require('child_process').exec;
const util = require('./util');
const fs = require('fs');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
const NOT_SUPPORTED = 'not supported';
// --------------------------
// Get current time and OS uptime
function time() {
let t = new Date().toString().split(' ');
return {
current: Date.now(),
uptime: os.uptime(),
timezone: (t.length >= 7) ? t[5] : '',
timezoneName: (t.length >= 7) ? t.slice(6).join(' ').replace(/\(/g, '').replace(/\)/g, '') : ''
};
}
exports.time = time;
// --------------------------
// Get logo filename of OS distribution
function getLogoFile(distro) {
distro = distro || '';
distro = distro.toLowerCase();
let result = _platform;
if (_windows) {
result = 'windows';
}
else if (distro.indexOf('mac os') !== -1) {
result = 'apple';
}
else if (distro.indexOf('arch') !== -1) {
result = 'arch';
}
else if (distro.indexOf('centos') !== -1) {
result = 'centos';
}
else if (distro.indexOf('coreos') !== -1) {
result = 'coreos';
}
else if (distro.indexOf('debian') !== -1) {
result = 'debian';
}
else if (distro.indexOf('deepin') !== -1) {
result = 'deepin';
}
else if (distro.indexOf('elementary') !== -1) {
result = 'elementary';
}
else if (distro.indexOf('fedora') !== -1) {
result = 'fedora';
}
else if (distro.indexOf('gentoo') !== -1) {
result = 'gentoo';
}
else if (distro.indexOf('mageia') !== -1) {
result = 'mageia';
}
else if (distro.indexOf('mandriva') !== -1) {
result = 'mandriva';
}
else if (distro.indexOf('manjaro') !== -1) {
result = 'manjaro';
}
else if (distro.indexOf('mint') !== -1) {
result = 'mint';
}
else if (distro.indexOf('mx') !== -1) {
result = 'mx';
}
else if (distro.indexOf('openbsd') !== -1) {
result = 'openbsd';
}
else if (distro.indexOf('freebsd') !== -1) {
result = 'freebsd';
}
else if (distro.indexOf('opensuse') !== -1) {
result = 'opensuse';
}
else if (distro.indexOf('pclinuxos') !== -1) {
result = 'pclinuxos';
}
else if (distro.indexOf('puppy') !== -1) {
result = 'puppy';
}
else if (distro.indexOf('raspbian') !== -1) {
result = 'raspbian';
}
else if (distro.indexOf('reactos') !== -1) {
result = 'reactos';
}
else if (distro.indexOf('redhat') !== -1) {
result = 'redhat';
}
else if (distro.indexOf('slackware') !== -1) {
result = 'slackware';
}
else if (distro.indexOf('sugar') !== -1) {
result = 'sugar';
}
else if (distro.indexOf('steam') !== -1) {
result = 'steam';
}
else if (distro.indexOf('suse') !== -1) {
result = 'suse';
}
else if (distro.indexOf('mate') !== -1) {
result = 'ubuntu-mate';
}
else if (distro.indexOf('lubuntu') !== -1) {
result = 'lubuntu';
}
else if (distro.indexOf('xubuntu') !== -1) {
result = 'xubuntu';
}
else if (distro.indexOf('ubuntu') !== -1) {
result = 'ubuntu';
}
else if (distro.indexOf('solaris') !== -1) {
result = 'solaris';
}
else if (distro.indexOf('tails') !== -1) {
result = 'tails';
}
else if (distro.indexOf('robolinux') !== -1) {
result = 'robolinux';
} else if (_linux && distro) {
result = distro.toLowerCase();
}
return result;
}
// --------------------------
// OS Information
function osInfo(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
platform: (_platform === 'Windows_NT' ? 'Windows' : _platform),
distro: 'unknown',
release: 'unknown',
codename: '',
kernel: os.release(),
arch: os.arch(),
hostname: os.hostname(),
codepage: '',
logofile: '',
serial: '',
build: '',
servicepack: ''
};
if (_linux) {
exec('cat /etc/*-release; cat /usr/lib/os-release; cat /etc/openwrt_release', function (error, stdout) {
//if (!error) {
/**
* @namespace
* @property {string} DISTRIB_ID
* @property {string} NAME
* @property {string} DISTRIB_RELEASE
* @property {string} VERSION_ID
* @property {string} DISTRIB_CODENAME
*/
let release = {};
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
if (line.indexOf('=') !== -1) {
release[line.split('=')[0].trim().toUpperCase()] = line.split('=')[1].trim();
}
});
let releaseVersion = (release.VERSION || '').replace(/"/g, '');
let codename = (release.DISTRIB_CODENAME || release.VERSION_CODENAME || '').replace(/"/g, '');
if (releaseVersion.indexOf('(') >= 0) {
codename = releaseVersion.split('(')[1].replace(/[()]/g, '').trim();
releaseVersion = releaseVersion.split('(')[0].trim();
}
result.distro = (release.DISTRIB_ID || release.NAME || 'unknown').replace(/"/g, '');
result.logofile = getLogoFile(result.distro);
result.release = (releaseVersion || release.DISTRIB_RELEASE || release.VERSION_ID || 'unknown').replace(/"/g, '');
result.codename = codename;
result.codepage = util.getCodepage();
result.build = (release.BUILD_ID || '').replace(/"/g, '').trim();
uuid().then(data => {
result.serial = data.os;
if (callback) {
callback(result);
}
resolve(result);
});
//}
});
}
if (_freebsd || _openbsd || _netbsd) {
exec('sysctl kern.ostype kern.osrelease kern.osrevision kern.hostuuid', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result.distro = util.getValue(lines, 'kern.ostype');
result.logofile = getLogoFile(result.distro);
result.release = util.getValue(lines, 'kern.osrelease').split('-')[0];
result.serial = util.getValue(lines, 'kern.uuid');
result.codename = '';
result.codepage = util.getCodepage();
}
if (callback) {
callback(result);
}
resolve(result);
});
}
if (_darwin) {
exec('sw_vers; sysctl kern.ostype kern.osrelease kern.osrevision kern.uuid', function (error, stdout) {
let lines = stdout.toString().split('\n');
result.serial = util.getValue(lines, 'kern.uuid');
result.distro = util.getValue(lines, 'ProductName');
result.release = util.getValue(lines, 'ProductVersion');
result.build = util.getValue(lines, 'BuildVersion');
result.logofile = getLogoFile(result.distro);
result.codename = 'macOS';
result.codename = (result.release.indexOf('10.4') > -1 ? 'Mac OS X Tiger' : result.codename);
result.codename = (result.release.indexOf('10.4') > -1 ? 'Mac OS X Tiger' : result.codename);
result.codename = (result.release.indexOf('10.4') > -1 ? 'Mac OS X Tiger' : result.codename);
result.codename = (result.release.indexOf('10.5') > -1 ? 'Mac OS X Leopard' : result.codename);
result.codename = (result.release.indexOf('10.6') > -1 ? 'Mac OS X Snow Leopard' : result.codename);
result.codename = (result.release.indexOf('10.7') > -1 ? 'Mac OS X Lion' : result.codename);
result.codename = (result.release.indexOf('10.8') > -1 ? 'OS X Mountain Lion' : result.codename);
result.codename = (result.release.indexOf('10.9') > -1 ? 'OS X Mavericks' : result.codename);
result.codename = (result.release.indexOf('10.10') > -1 ? 'OS X Yosemite' : result.codename);
result.codename = (result.release.indexOf('10.11') > -1 ? 'OS X El Capitan' : result.codename);
result.codename = (result.release.indexOf('10.12') > -1 ? 'macOS Sierra' : result.codename);
result.codename = (result.release.indexOf('10.13') > -1 ? 'macOS High Sierra' : result.codename);
result.codename = (result.release.indexOf('10.14') > -1 ? 'macOS Mojave' : result.codename);
result.codepage = util.getCodepage();
if (callback) {
callback(result);
}
resolve(result);
});
}
if (_sunos) {
result.release = result.kernel;
exec('uname -o', function (error, stdout) {
let lines = stdout.toString().split('\n');
result.distro = lines[0];
result.logofile = getLogoFile(result.distro);
if (callback) { callback(result); }
resolve(result);
});
}
if (_windows) {
result.logofile = getLogoFile();
result.release = result.kernel;
try {
util.wmic('os get /value').then((stdout) => {
let lines = stdout.toString().split('\r\n');
result.distro = util.getValue(lines, 'Caption', '=').trim();
result.serial = util.getValue(lines, 'SerialNumber', '=').trim();
result.build = util.getValue(lines, 'BuildNumber', '=').trim();
result.servicepack = util.getValue(lines, 'ServicePackMajorVersion', '=').trim() + '.' + util.getValue(lines, 'ServicePackMinorVersion', '=').trim();
result.codepage = util.getCodepage();
if (callback) {
callback(result);
}
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.osInfo = osInfo;
function versions(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
kernel: os.release(),
openssl: process.versions.openssl,
systemOpenssl: '',
systemOpensslLib: '',
node: process.versions.node,
v8: process.versions.v8,
npm: '',
yarn: '',
pm2: '',
gulp: '',
grunt: '',
git: '',
tsc: '',
mysql: '',
redis: '',
mongodb: '',
apache: '',
nginx: '',
php: '',
docker: '',
postfix: '',
postgresql: '',
perl: '',
python: '',
python3: '',
pip: '',
pip3: '',
java: '',
gcc: '',
virtualbox: ''
};
let functionProcessed = (function () {
let totalFunctions = 25;
return function () {
if (--totalFunctions === 0) {
if (callback) {
callback(result);
}
resolve(result);
}
};
})();
try {
exec('openssl version', function (error, stdout) {
if (!error) {
let openssl_string = stdout.toString().split('\n')[0].trim();
let openssl = openssl_string.split(' ');
result.systemOpenssl = openssl.length > 0 ? openssl[1] : openssl[0];
result.systemOpensslLib = openssl.length > 0 ? openssl[0] : 'openssl';
}
functionProcessed();
});
exec('npm -v', function (error, stdout) {
if (!error) {
result.npm = stdout.toString().split('\n')[0];
}
functionProcessed();
});
exec('pm2 -v', function (error, stdout) {
if (!error) {
let pm2 = stdout.toString().split('\n')[0].trim();
if (!pm2.startsWith('[PM2]')) {
result.pm2 = pm2;
}
}
functionProcessed();
});
exec('yarn --version', function (error, stdout) {
if (!error) {
result.yarn = stdout.toString().split('\n')[0];
}
functionProcessed();
});
exec('gulp --version', function (error, stdout) {
if (!error) {
const gulp = stdout.toString().split('\n')[0] || '';
result.gulp = (gulp.toLowerCase().split('version')[1] || '').trim();
}
functionProcessed();
});
exec('tsc --version', function (error, stdout) {
if (!error) {
const tsc = stdout.toString().split('\n')[0] || '';
result.tsc = (tsc.toLowerCase().split('version')[1] || '').trim();
}
functionProcessed();
});
exec('grunt --version', function (error, stdout) {
if (!error) {
const grunt = stdout.toString().split('\n')[0] || '';
result.grunt = (grunt.toLowerCase().split('cli v')[1] || '').trim();
}
functionProcessed();
});
if (_darwin) {
const gitHomebrewExists = fs.existsSync('/usr/local/Cellar/git');
if (util.darwinXcodeExists() || gitHomebrewExists) {
exec('git --version', function (error, stdout) {
if (!error) {
let git = stdout.toString().split('\n')[0] || '';
git = (git.toLowerCase().split('version')[1] || '').trim();
result.git = (git.split(' ')[0] || '').trim();
}
functionProcessed();
});
} else {
functionProcessed();
}
} else {
exec('git --version', function (error, stdout) {
if (!error) {
let git = stdout.toString().split('\n')[0] || '';
git = (git.toLowerCase().split('version')[1] || '').trim();
result.git = (git.split(' ')[0] || '').trim();
}
functionProcessed();
});
}
exec('apachectl -v 2>&1', function (error, stdout) {
if (!error) {
const apache = (stdout.toString().split('\n')[0] || '').split(':');
result.apache = (apache.length > 1 ? apache[1].replace('Apache', '').replace('/', '').trim() : '');
}
functionProcessed();
});
exec('nginx -v 2>&1', function (error, stdout) {
if (!error) {
const nginx = stdout.toString().split('\n')[0] || '';
result.nginx = (nginx.toLowerCase().split('/')[1] || '').trim();
}
functionProcessed();
});
exec('mysql -V', function (error, stdout) {
if (!error) {
let mysql = stdout.toString().split('\n')[0] || '';
mysql = (mysql.toLowerCase().split(',')[0] || '').trim();
const parts = mysql.split(' ');
result.mysql = (parts[parts.length - 1] || '').trim();
}
functionProcessed();
});
exec('php -v', function (error, stdout) {
if (!error) {
const php = stdout.toString().split('\n')[0] || '';
let parts = php.split('(');
if (parts[0].indexOf('-')) {
parts = parts[0].split('-');
}
result.php = parts[0].replace(/[^0-9.]/g, '');
}
functionProcessed();
});
exec('redis-server --version', function (error, stdout) {
if (!error) {
const redis = stdout.toString().split('\n')[0] || '';
const parts = redis.split(' ');
result.redis = util.getValue(parts, 'v', '=', true);
}
functionProcessed();
});
exec('docker --version', function (error, stdout) {
if (!error) {
const docker = stdout.toString().split('\n')[0] || '';
const parts = docker.split(' ');
result.docker = parts.length > 2 && parts[2].endsWith(',') ? parts[2].slice(0, -1) : '';
}
functionProcessed();
});
exec('postconf -d | grep mail_version', function (error, stdout) {
if (!error) {
const postfix = stdout.toString().split('\n') || [];
result.postfix = util.getValue(postfix, 'mail_version', '=', true);
}
functionProcessed();
});
exec('mongod --version', function (error, stdout) {
if (!error) {
const mongodb = stdout.toString().split('\n')[0] || '';
result.mongodb = (mongodb.toLowerCase().split(',')[0] || '').replace(/[^0-9.]/g, '');
}
functionProcessed();
});
if (_linux) {
exec('locate bin/postgres', function (error, stdout) {
if (!error) {
const postgresqlBin = stdout.toString().split('\n').sort();
if (postgresqlBin.length) {
exec(postgresqlBin[postgresqlBin.length - 1] + ' -V', function (error, stdout) {
if (!error) {
const postgresql = stdout.toString().split('\n')[0].split(' ') || [];
result.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : '';
}
functionProcessed();
});
} else {
functionProcessed();
}
} else {
functionProcessed();
}
});
} else {
if (_windows) {
util.wmic('service get /value').then((stdout) => {
let serviceSections = stdout.split(/\n\s*\n/);
for (let i = 0; i < serviceSections.length; i++) {
if (serviceSections[i].trim() !== '') {
let lines = serviceSections[i].trim().split('\r\n');
let srvCaption = util.getValue(lines, 'caption', '=', true).toLowerCase();
if (srvCaption.indexOf('postgresql') > -1) {
const parts = srvCaption.split(' server ');
if (parts.length > 1) {
result.postgresql = parts[1];
}
}
}
}
functionProcessed();
});
} else {
exec('postgres -V', function (error, stdout) {
if (!error) {
const postgresql = stdout.toString().split('\n')[0].split(' ') || [];
result.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : '';
}
functionProcessed();
});
}
}
exec('perl -v', function (error, stdout) {
if (!error) {
const perl = stdout.toString().split('\n') || '';
while (perl.length > 0 && perl[0].trim() === '') {
perl.shift();
}
if (perl.length > 0) {
result.perl = perl[0].split('(').pop().split(')')[0].replace('v', '');
}
}
functionProcessed();
});
exec('python -V 2>&1', function (error, stdout) {
if (!error) {
const python = stdout.toString().split('\n')[0] || '';
result.python = python.toLowerCase().replace('python', '').trim();
}
functionProcessed();
});
exec('python3 -V 2>&1', function (error, stdout) {
if (!error) {
const python = stdout.toString().split('\n')[0] || '';
result.python3 = python.toLowerCase().replace('python', '').trim();
}
functionProcessed();
});
exec('pip -V 2>&1', function (error, stdout) {
if (!error) {
const pip = stdout.toString().split('\n')[0] || '';
const parts = pip.split(' ');
result.pip = parts.length >= 2 ? parts[1] : '';
}
functionProcessed();
});
exec('pip3 -V 2>&1', function (error, stdout) {
if (!error) {
const pip = stdout.toString().split('\n')[0] || '';
const parts = pip.split(' ');
result.pip3 = parts.length >= 2 ? parts[1] : '';
}
functionProcessed();
});
if (_darwin) {
// check if any JVM is installed but avoid dialog box that Java needs to be installed
exec('/usr/libexec/java_home -V 2>&1', function (error, stdout) {
if (!error && stdout.toString().toLowerCase().indexOf('no java runtime') === -1) {
// now this can be done savely
exec('java -version 2>&1', function (error, stdout) {
if (!error) {
const java = stdout.toString().split('\n')[0] || '';
const parts = java.split('"');
result.java = parts.length === 3 ? parts[1].trim() : '';
}
functionProcessed();
});
} else {
functionProcessed();
}
});
} else {
exec('java -version 2>&1', function (error, stdout) {
if (!error) {
const java = stdout.toString().split('\n')[0] || '';
const parts = java.split('"');
result.java = parts.length === 3 ? parts[1].trim() : '';
}
functionProcessed();
});
}
if ((_darwin && util.darwinXcodeExists()) || !_darwin) {
exec('gcc -dumpversion', function (error, stdout) {
if (!error) {
result.gcc = stdout.toString().split('\n')[0].trim() || '';
}
if (result.gcc.indexOf('.') > -1) {
functionProcessed();
} else {
exec('gcc --version', function (error, stdout) {
if (!error) {
const gcc = stdout.toString().split('\n')[0].trim();
if (gcc.indexOf('gcc') > -1 && gcc.indexOf(')') > -1) {
const parts = gcc.split(')');
result.gcc = parts[1].trim() || result.gcc;
}
}
functionProcessed();
});
}
});
} else {
functionProcessed();
}
exec(util.getVboxmanage() + ' -v 2>&1', function (error, stdout) {
if (!error) {
const vbox = stdout.toString().split('\n')[0] || '';
const parts = vbox.split('r');
result.virtualbox = parts[0];
}
functionProcessed();
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
});
});
}
exports.versions = versions;
function shell(callback) {
return new Promise((resolve, reject) => {
process.nextTick(() => {
if (_windows) {
let error = new Error(NOT_SUPPORTED);
if (callback) {
callback(NOT_SUPPORTED);
}
reject(error);
}
let result = '';
exec('echo $SHELL', function (error, stdout) {
if (!error) {
result = stdout.toString().split('\n')[0];
}
if (callback) {
callback(result);
}
resolve(result);
});
});
});
}
exports.shell = shell;
function uuid(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
os: ''
};
let parts;
if (_darwin) {
exec('ioreg -rd1 -c IOPlatformExpertDevice | grep IOPlatformUUID', function (error, stdout) {
if (!error) {
parts = stdout.toString().split('\n')[0].replace(/"/g, '').split('=');
result.os = parts.length > 1 ? parts[1].trim().toLowerCase() : '';
}
if (callback) {
callback(result);
}
resolve(result);
});
}
if (_linux) {
exec('( cat /var/lib/dbus/machine-id /etc/machine-id 2> /dev/null || hostname ) | head -n 1 || :', function (error, stdout) {
if (!error) {
result.os = stdout.toString().split('\n')[0].trim().toLowerCase();
}
if (callback) {
callback(result);
}
resolve(result);
});
}
if (_freebsd || _openbsd || _netbsd) {
exec('kenv -q smbios.system.uuid', function (error, stdout) {
if (!error) {
result.os = stdout.toString().split('\n')[0].trim().toLowerCase();
}
if (callback) {
callback(result);
}
resolve(result);
});
}
if (_windows) {
exec('%windir%\\System32\\reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography" /v MachineGuid', util.execOptsWin, function (error, stdout) {
if (!error) {
parts = stdout.toString().split('\n\r')[0].split('REG_SZ');
result.os = parts.length > 1 ? parts[1].replace(/\r+|\n+|\s+/ig, '').toLowerCase() : '';
}
if (callback) {
callback(result);
}
resolve(result);
});
}
});
});
}
exports.uuid = uuid;
'use strict';
// @ts-check
// ==================================================================================
// processes.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 10. Processes
// ----------------------------------------------------------------------------------
const os = require('os');
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;
const util = require('./util');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
let _processes_cpu = {
all: 0,
list: {},
ms: 0,
result: {}
};
let _services_cpu = {
all: 0,
list: {},
ms: 0,
result: {}
};
let _process_cpu = {
all: 0,
list: {},
ms: 0,
result: {}
};
let _winStatusValues = {
'0': 'unknown',
'1': 'other',
'2': 'ready',
'3': 'running',
'4': 'blocked',
'5': 'suspended blocked',
'6': 'suspended ready',
'7': 'terminated',
'8': 'stopped',
'9': 'growing',
};
function parseTimeWin(time) {
time = time || '';
if (time) {
return (time.substr(0, 4) + '-' + time.substr(4, 2) + '-' + time.substr(6, 2) + ' ' + time.substr(8, 2) + ':' + time.substr(10, 2) + ':' + time.substr(12, 2));
} else {
return '';
}
}
function parseTimeUnix(time) {
let result = time;
let parts = time.replace(/ +/g, ' ').split(' ');
if (parts.length === 5) {
result = parts[4] + '-' + ('0' + ('JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'.indexOf(parts[1].toUpperCase()) / 3 + 1)).slice(-2) + '-' + ('0' + parts[2]).slice(-2) + ' ' + parts[3];
}
return result;
}
// --------------------------
// PS - services
// pass a comma separated string with services to check (mysql, apache, postgresql, ...)
// this function gives an array back, if the services are running.
function services(srv, callback) {
// fallback - if only callback is given
if (util.isFunction(srv) && !callback) {
callback = srv;
srv = '';
}
return new Promise((resolve) => {
process.nextTick(() => {
if (srv) {
srv = srv.trim().toLowerCase().replace(/,+/g, ' ').replace(/ +/g, ' ').replace(/ +/g, '|');
let srvs = srv.split('|');
let result = [];
let dataSrv = [];
let allSrv = [];
if (_linux || _freebsd || _openbsd || _netbsd || _darwin) {
if ((_linux || _freebsd || _openbsd || _netbsd) && srv === '*') {
srv = '';
let tmpsrv = execSync('service --status-all 2> /dev/null').toString().split('\n');
for (const s of tmpsrv) {
const parts = s.split(']');
if (parts.length === 2) {
srv += (srv !== '' ? '|' : '') + parts[1].trim();
allSrv.push({ name: parts[1].trim(), running: parts[0].indexOf('+') > 0 });
}
}
srvs = srv.split('|');
}
let comm = (_darwin) ? 'ps -caxo pcpu,pmem,pid,command' : 'ps -axo pcpu,pmem,pid,command';
if (srv !== '' && srvs.length > 0) {
exec(comm + ' | grep -v grep | grep -iE "' + srv + '"', { maxBuffer: 1024 * 20000 }, function (error, stdout) {
if (!error) {
let lines = stdout.toString().replace(/ +/g, ' ').replace(/,+/g, '.').split('\n');
srvs.forEach(function (srv) {
let ps;
if (_darwin) {
ps = lines.filter(function (e) {
return (e.toLowerCase().indexOf(srv) !== -1);
});
} else {
ps = lines.filter(function (e) {
return (e.toLowerCase().indexOf(' ' + srv + ':') !== -1) || (e.toLowerCase().indexOf('/' + srv) !== -1);
});
}
let singleSrv = allSrv.filter(item => { return item.name === srv; });
const pids = [];
for (const p of ps) {
pids.push(p.trim().split(' ')[2]);
}
result.push({
name: srv,
running: (allSrv.length && singleSrv.length ? singleSrv[0].running : ps.length > 0),
startmode: '',
pids: pids,
pcpu: parseFloat((ps.reduce(function (pv, cv) {
return pv + parseFloat(cv.trim().split(' ')[0]);
}, 0)).toFixed(2)),
pmem: parseFloat((ps.reduce(function (pv, cv) {
return pv + parseFloat(cv.trim().split(' ')[1]);
}, 0)).toFixed(2))
});
});
if (_linux) {
// calc process_cpu - ps is not accurate in linux!
let cmd = 'cat /proc/stat | grep "cpu "';
for (let i in result) {
for (let j in result[i].pids) {
cmd += (';cat /proc/' + result[i].pids[j] + '/stat');
}
}
exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
let curr_processes = stdout.toString().split('\n');
// first line (all - /proc/stat)
let all = parseProcStat(curr_processes.shift());
// process
let list_new = {};
let resultProcess = {};
for (let i = 0; i < curr_processes.length; i++) {
resultProcess = calcProcStatLinux(curr_processes[i], all, _services_cpu);
if (resultProcess.pid) {
let listPos = -1;
for (let i in result) {
for (let j in result[i].pids) {
if (parseInt(result[i].pids[j]) === parseInt(resultProcess.pid)) {
listPos = i;
}
}
}
if (listPos >= 0) {
result[listPos].pcpu += resultProcess.pcpuu + resultProcess.pcpus;
}
// save new values
list_new[resultProcess.pid] = {
pcpuu: resultProcess.pcpuu,
pcpus: resultProcess.pcpus,
utime: resultProcess.utime,
stime: resultProcess.stime,
cutime: resultProcess.cutime,
cstime: resultProcess.cstime
};
}
}
// store old values
_services_cpu.all = all;
_services_cpu.list = list_new;
_services_cpu.ms = Date.now() - _services_cpu.ms;
_services_cpu.result = result;
if (callback) { callback(result); }
resolve(result);
});
} else {
if (callback) { callback(result); }
resolve(result);
}
} else {
exec('ps -o comm | grep -v grep | egrep "' + srv + '"', { maxBuffer: 1024 * 20000 }, function (error, stdout) {
if (!error) {
let lines = stdout.toString().replace(/ +/g, ' ').replace(/,+/g, '.').split('\n');
srvs.forEach(function (srv) {
let ps = lines.filter(function (e) {
return e.indexOf(srv) !== -1;
});
result.push({
name: srv,
running: ps.length > 0,
startmode: '',
pcpu: 0,
pmem: 0
});
});
if (callback) { callback(result); }
resolve(result);
} else {
srvs.forEach(function (srv) {
result.push({
name: srv,
running: false,
startmode: '',
pcpu: 0,
pmem: 0
});
});
if (callback) { callback(result); }
resolve(result);
}
});
}
});
} else {
if (callback) { callback(result); }
resolve(result);
}
}
if (_windows) {
try {
util.wmic('service get /value').then((stdout, error) => {
if (!error) {
let serviceSections = stdout.split(/\n\s*\n/);
for (let i = 0; i < serviceSections.length; i++) {
if (serviceSections[i].trim() !== '') {
let lines = serviceSections[i].trim().split('\r\n');
let srvName = util.getValue(lines, 'Name', '=', true).toLowerCase();
let started = util.getValue(lines, 'Started', '=', true);
let startMode = util.getValue(lines, 'StartMode', '=', true);
if (srv === '*' || srvs.indexOf(srvName) >= 0) {
result.push({
name: srvName,
running: (started === 'TRUE'),
startmode: startMode,
pcpu: 0,
pmem: 0
});
dataSrv.push(srvName);
}
}
}
if (srv !== '*') {
let srvsMissing = srvs.filter(function (e) {
return dataSrv.indexOf(e) === -1;
});
srvsMissing.forEach(function (srvName) {
result.push({
name: srvName,
running: false,
startmode: '',
pcpu: 0,
pmem: 0
});
});
}
if (callback) { callback(result); }
resolve(result);
} else {
srvs.forEach(function (srvName) {
result.push({
name: srvName,
running: false,
startmode: '',
pcpu: 0,
pmem: 0
});
});
if (callback) { callback(result); }
resolve(result);
}
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
} else {
if (callback) { callback({}); }
resolve({});
}
});
});
}
exports.services = services;
function parseProcStat(line) {
let parts = line.replace(/ +/g, ' ').split(' ');
let user = (parts.length >= 2 ? parseInt(parts[1]) : 0);
let nice = (parts.length >= 3 ? parseInt(parts[2]) : 0);
let system = (parts.length >= 4 ? parseInt(parts[3]) : 0);
let idle = (parts.length >= 5 ? parseInt(parts[4]) : 0);
let iowait = (parts.length >= 6 ? parseInt(parts[5]) : 0);
let irq = (parts.length >= 7 ? parseInt(parts[6]) : 0);
let softirq = (parts.length >= 8 ? parseInt(parts[7]) : 0);
let steal = (parts.length >= 9 ? parseInt(parts[8]) : 0);
let guest = (parts.length >= 10 ? parseInt(parts[9]) : 0);
let guest_nice = (parts.length >= 11 ? parseInt(parts[10]) : 0);
return user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice;
}
function calcProcStatLinux(line, all, _cpu_old) {
let statparts = line.replace(/ +/g, ' ').split(')');
if (statparts.length >= 2) {
let parts = statparts[1].split(' ');
if (parts.length >= 16) {
let pid = parseInt(statparts[0].split(' ')[0]);
let utime = parseInt(parts[12]);
let stime = parseInt(parts[13]);
let cutime = parseInt(parts[14]);
let cstime = parseInt(parts[15]);
// calc
let pcpuu = 0;
let pcpus = 0;
if (_cpu_old.all > 0 && _cpu_old.list[pid]) {
pcpuu = (utime + cutime - _cpu_old.list[pid].utime - _cpu_old.list[pid].cutime) / (all - _cpu_old.all) * 100; // user
pcpus = (stime + cstime - _cpu_old.list[pid].stime - _cpu_old.list[pid].cstime) / (all - _cpu_old.all) * 100; // system
} else {
pcpuu = (utime + cutime) / (all) * 100; // user
pcpus = (stime + cstime) / (all) * 100; // system
}
return {
pid: pid,
utime: utime,
stime: stime,
cutime: cutime,
cstime: cstime,
pcpuu: pcpuu,
pcpus: pcpus
};
} else {
return {
pid: 0,
utime: 0,
stime: 0,
cutime: 0,
cstime: 0,
pcpuu: 0,
pcpus: 0
};
}
} else {
return {
pid: 0,
utime: 0,
stime: 0,
cutime: 0,
cstime: 0,
pcpuu: 0,
pcpus: 0
};
}
}
function calcProcStatWin(procStat, all, _cpu_old) {
// calc
let pcpuu = 0;
let pcpus = 0;
if (_cpu_old.all > 0 && _cpu_old.list[procStat.pid]) {
pcpuu = (procStat.utime - _cpu_old.list[procStat.pid].utime) / (all - _cpu_old.all) * 100; // user
pcpus = (procStat.stime - _cpu_old.list[procStat.pid].stime) / (all - _cpu_old.all) * 100; // system
} else {
pcpuu = (procStat.utime) / (all) * 100; // user
pcpus = (procStat.stime) / (all) * 100; // system
}
return {
pid: procStat.pid,
utime: procStat.utime,
stime: procStat.stime,
pcpuu: pcpuu,
pcpus: pcpus
};
}
// --------------------------
// running processes
function processes(callback) {
let parsedhead = [];
function getName(command) {
command = command || '';
let result = command.split(' ')[0];
if (result.substr(-1) === ':') {
result = result.substr(0, result.length - 1);
}
if (result.substr(0, 1) !== '[') {
let parts = result.split('/');
if (isNaN(parseInt(parts[parts.length - 1]))) {
result = parts[parts.length - 1];
} else {
result = parts[0];
}
}
return result;
}
function parseLine(line) {
let offset = 0;
let offset2 = 0;
function checkColumn(i) {
offset = offset2;
offset2 = line.substring(parsedhead[i].to + offset, 1000).indexOf(' ');
}
checkColumn(0);
const pid = parseInt(line.substring(parsedhead[0].from + offset, parsedhead[0].to + offset2));
checkColumn(1);
const ppid = parseInt(line.substring(parsedhead[1].from + offset, parsedhead[1].to + offset2));
checkColumn(2);
const pcpu = parseFloat(line.substring(parsedhead[2].from + offset, parsedhead[2].to + offset2).replace(/,/g, '.'));
checkColumn(3);
const pmem = parseFloat(line.substring(parsedhead[3].from + offset, parsedhead[3].to + offset2).replace(/,/g, '.'));
checkColumn(4);
const priority = parseInt(line.substring(parsedhead[4].from + offset, parsedhead[4].to + offset2));
checkColumn(5);
const vsz = parseInt(line.substring(parsedhead[5].from + offset, parsedhead[5].to + offset2));
checkColumn(6);
const rss = parseInt(line.substring(parsedhead[6].from + offset, parsedhead[6].to + offset2));
checkColumn(7);
const nice = parseInt(line.substring(parsedhead[7].from + offset, parsedhead[7].to + offset2)) || 0;
checkColumn(8);
const started = parseTimeUnix(line.substring(parsedhead[8].from + offset, parsedhead[8].to + offset2).trim());
checkColumn(9);
let state = line.substring(parsedhead[9].from + offset, parsedhead[9].to + offset2).trim();
state = (state[0] === 'R' ? 'running' : (state[0] === 'S' ? 'sleeping' : (state[0] === 'T' ? 'stopped' : (state[0] === 'W' ? 'paging' : (state[0] === 'X' ? 'dead' : (state[0] === 'Z' ? 'zombie' : ((state[0] === 'D' || state[0] === 'U') ? 'blocked' : 'unknown')))))));
checkColumn(10);
let tty = line.substring(parsedhead[10].from + offset, parsedhead[10].to + offset2).trim();
if (tty === '?' || tty === '??') tty = '';
checkColumn(11);
const user = line.substring(parsedhead[11].from + offset, parsedhead[11].to + offset2).trim();
checkColumn(12);
const fullcommand = line.substring(parsedhead[12].from + offset, parsedhead[12].to + offset2).trim().replace(/\[/g, '').replace(/]/g, '');
let path = '';
let command = '';
let params = '';
// try to figure out where parameter starts
let firstParamPos = fullcommand.indexOf(' -');
let firstParamPathPos = fullcommand.indexOf(' /');
firstParamPos = (firstParamPos >= 0 ? firstParamPos : 10000);
firstParamPathPos = (firstParamPathPos >= 0 ? firstParamPathPos : 10000);
const firstPos = Math.min(firstParamPos, firstParamPathPos);
let tmpCommand = fullcommand.substr(0, firstPos);
const tmpParams = fullcommand.substr(firstPos);
const lastSlashPos = tmpCommand.lastIndexOf('/');
if (lastSlashPos >= 0) {
path = tmpCommand.substr(0, lastSlashPos);
tmpCommand = tmpCommand.substr(lastSlashPos + 1);
}
if (firstPos === 10000) {
const parts = tmpCommand.split(' ');
command = parts.shift();
params = (parts.join(' ') + ' ' + tmpParams).trim();
} else {
command = tmpCommand.trim();
params = tmpParams.trim();
}
return ({
pid: pid,
parentPid: ppid,
name: _linux ? getName(command) : command,
pcpu: pcpu,
pcpuu: 0,
pcpus: 0,
pmem: pmem,
priority: priority,
mem_vsz: vsz,
mem_rss: rss,
nice: nice,
started: started,
state: state,
tty: tty,
user: user,
command: command,
params: params,
path: path
});
}
function parseProcesses(lines) {
let result = [];
if (lines.length > 1) {
let head = lines[0];
parsedhead = util.parseHead(head, 8);
lines.shift();
lines.forEach(function (line) {
if (line.trim() !== '') {
result.push(parseLine(line));
}
});
}
return result;
}
function parseProcesses2(lines) {
function formatDateTime(time) {
const month = ('0' + (time.getMonth() + 1).toString()).substr(-2);
const year = time.getFullYear().toString();
const day = ('0' + time.getDay().toString()).substr(-2);
const hours = time.getHours().toString();
const mins = time.getMinutes().toString();
const secs = ('0' + time.getSeconds().toString()).substr(-2);
return (year + '-' + month + '-' + day + ' ' + hours + ':' + mins + ':' + secs);
}
let result = [];
lines.forEach(function (line) {
if (line.trim() !== '') {
line = line.trim().replace(/ +/g, ' ').replace(/,+/g, '.');
const parts = line.split(' ');
const command = parts.slice(9).join(' ');
const pmem = parseFloat((1.0 * parseInt(parts[3]) * 1024 / os.totalmem()).toFixed(1));
const elapsed_parts = parts[5].split(':');
const started = formatDateTime(new Date(Date.now() - (elapsed_parts.length > 1 ? (elapsed_parts[0] * 60 + elapsed_parts[1]) * 1000 : elapsed_parts[0] * 1000)));
result.push({
pid: parseInt(parts[0]),
parentPid: parseInt(parts[1]),
name: getName(command),
pcpu: 0,
pcpuu: 0,
pcpus: 0,
pmem: pmem,
priority: 0,
mem_vsz: parseInt(parts[2]),
mem_rss: parseInt(parts[3]),
nice: parseInt(parts[4]),
started: started,
state: (parts[6] === 'R' ? 'running' : (parts[6] === 'S' ? 'sleeping' : (parts[6] === 'T' ? 'stopped' : (parts[6] === 'W' ? 'paging' : (parts[6] === 'X' ? 'dead' : (parts[6] === 'Z' ? 'zombie' : ((parts[6] === 'D' || parts[6] === 'U') ? 'blocked' : 'unknown'))))))),
tty: parts[7],
user: parts[8],
command: command
});
}
});
return result;
}
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
all: 0,
running: 0,
blocked: 0,
sleeping: 0,
unknown: 0,
list: []
};
let cmd = '';
if ((_processes_cpu.ms && Date.now() - _processes_cpu.ms >= 500) || _processes_cpu.ms === 0) {
if (_linux || _freebsd || _openbsd || _netbsd || _darwin || _sunos) {
if (_linux) cmd = 'export LC_ALL=C; ps -axo pid:11,ppid:11,pcpu:6,pmem:6,pri:5,vsz:11,rss:11,ni:5,lstart:30,state:5,tty:15,user:20,command; unset LC_ALL';
if (_freebsd || _openbsd || _netbsd) cmd = 'export LC_ALL=C; ps -axo pid,ppid,pcpu,pmem,pri,vsz,rss,ni,lstart,state,tty,user,command; unset LC_ALL';
if (_darwin) cmd = 'export LC_ALL=C; ps -axo pid,ppid,pcpu,pmem,pri,vsz,rss,nice,lstart,state,tty,user,command -r; unset LC_ALL';
if (_sunos) cmd = 'ps -Ao pid,ppid,pcpu,pmem,pri,vsz,rss,nice,stime,s,tty,user,comm';
exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
if (!error) {
result.list = parseProcesses(stdout.toString().split('\n'));
result.all = result.list.length;
result.running = result.list.filter(function (e) {
return e.state === 'running';
}).length;
result.blocked = result.list.filter(function (e) {
return e.state === 'blocked';
}).length;
result.sleeping = result.list.filter(function (e) {
return e.state === 'sleeping';
}).length;
if (_linux) {
// calc process_cpu - ps is not accurate in linux!
cmd = 'cat /proc/stat | grep "cpu "';
for (let i = 0; i < result.list.length; i++) {
cmd += (';cat /proc/' + result.list[i].pid + '/stat');
}
exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
let curr_processes = stdout.toString().split('\n');
// first line (all - /proc/stat)
let all = parseProcStat(curr_processes.shift());
// process
let list_new = {};
let resultProcess = {};
for (let i = 0; i < curr_processes.length; i++) {
resultProcess = calcProcStatLinux(curr_processes[i], all, _processes_cpu);
if (resultProcess.pid) {
// store pcpu in outer array
let listPos = result.list.map(function (e) { return e.pid; }).indexOf(resultProcess.pid);
if (listPos >= 0) {
result.list[listPos].pcpu = resultProcess.pcpuu + resultProcess.pcpus;
result.list[listPos].pcpuu = resultProcess.pcpuu;
result.list[listPos].pcpus = resultProcess.pcpus;
}
// save new values
list_new[resultProcess.pid] = {
pcpuu: resultProcess.pcpuu,
pcpus: resultProcess.pcpus,
utime: resultProcess.utime,
stime: resultProcess.stime,
cutime: resultProcess.cutime,
cstime: resultProcess.cstime
};
}
}
// store old values
_processes_cpu.all = all;
_processes_cpu.list = list_new;
_processes_cpu.ms = Date.now() - _processes_cpu.ms;
_processes_cpu.result = result;
if (callback) { callback(result); }
resolve(result);
});
} else {
if (callback) { callback(result); }
resolve(result);
}
} else {
cmd = 'ps -o pid,ppid,vsz,rss,nice,etime,stat,tty,user,comm';
if (_sunos) {
cmd = 'ps -o pid,ppid,vsz,rss,nice,etime,s,tty,user,comm';
}
exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.shift();
result.list = parseProcesses2(lines);
result.all = result.list.length;
result.running = result.list.filter(function (e) {
return e.state === 'running';
}).length;
result.blocked = result.list.filter(function (e) {
return e.state === 'blocked';
}).length;
result.sleeping = result.list.filter(function (e) {
return e.state === 'sleeping';
}).length;
if (callback) { callback(result); }
resolve(result);
} else {
if (callback) { callback(result); }
resolve(result);
}
});
}
});
}
if (_windows) {
try {
util.wmic('process get /value').then((stdout, error) => {
if (!error) {
let processSections = stdout.split(/\n\s*\n/);
let procs = [];
let procStats = [];
let list_new = {};
let allcpuu = 0;
let allcpus = 0;
for (let i = 0; i < processSections.length; i++) {
if (processSections[i].trim() !== '') {
let lines = processSections[i].trim().split('\r\n');
let pid = parseInt(util.getValue(lines, 'ProcessId', '=', true), 10);
let parentPid = parseInt(util.getValue(lines, 'ParentProcessId', '=', true), 10);
let statusValue = util.getValue(lines, 'ExecutionState', '=');
let name = util.getValue(lines, 'Caption', '=', true);
let commandLine = util.getValue(lines, 'CommandLine', '=', true);
let commandPath = util.getValue(lines, 'ExecutablePath', '=', true);
let utime = parseInt(util.getValue(lines, 'UserModeTime', '=', true), 10);
let stime = parseInt(util.getValue(lines, 'KernelModeTime', '=', true), 10);
let mem = parseInt(util.getValue(lines, 'WorkingSetSize', '=', true), 10);
allcpuu = allcpuu + utime;
allcpus = allcpus + stime;
result.all++;
if (!statusValue) { result.unknown++; }
if (statusValue === '3') { result.running++; }
if (statusValue === '4' || statusValue === '5') { result.blocked++; }
procStats.push({
pid: pid,
utime: utime,
stime: stime,
pcpu: 0,
pcpuu: 0,
pcpus: 0,
});
procs.push({
pid: pid,
parentPid: parentPid,
name: name,
pcpu: 0,
pcpuu: 0,
pcpus: 0,
pmem: mem / os.totalmem() * 100,
priority: parseInt(util.getValue(lines, 'Priority', '=', true), 10),
mem_vsz: parseInt(util.getValue(lines, 'PageFileUsage', '=', true), 10),
mem_rss: Math.floor(parseInt(util.getValue(lines, 'WorkingSetSize', '=', true), 10) / 1024),
nice: 0,
started: parseTimeWin(util.getValue(lines, 'CreationDate', '=', true)),
state: (!statusValue ? _winStatusValues[0] : _winStatusValues[statusValue]),
tty: '',
user: '',
command: commandLine || name,
path: commandPath,
params: ''
});
}
}
result.sleeping = result.all - result.running - result.blocked - result.unknown;
result.list = procs;
for (let i = 0; i < procStats.length; i++) {
let resultProcess = calcProcStatWin(procStats[i], allcpuu + allcpus, _processes_cpu);
// store pcpu in outer array
let listPos = result.list.map(function (e) { return e.pid; }).indexOf(resultProcess.pid);
if (listPos >= 0) {
result.list[listPos].pcpu = resultProcess.pcpuu + resultProcess.pcpus;
result.list[listPos].pcpuu = resultProcess.pcpuu;
result.list[listPos].pcpus = resultProcess.pcpus;
}
// save new values
list_new[resultProcess.pid] = {
pcpuu: resultProcess.pcpuu,
pcpus: resultProcess.pcpus,
utime: resultProcess.utime,
stime: resultProcess.stime
};
}
// store old values
_processes_cpu.all = allcpuu + allcpus;
_processes_cpu.list = list_new;
_processes_cpu.ms = Date.now() - _processes_cpu.ms;
_processes_cpu.result = result;
}
if (callback) {
callback(result);
}
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
} else {
if (callback) { callback(_processes_cpu.result); }
resolve(_processes_cpu.result);
}
});
});
}
exports.processes = processes;
// --------------------------
// PS - process load
// get detailed information about a certain process
// (PID, CPU-Usage %, Mem-Usage %)
function processLoad(proc, callback) {
// fallback - if only callback is given
if (util.isFunction(proc) && !callback) {
callback = proc;
proc = '';
}
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
'proc': proc,
'pid': -1,
'cpu': 0,
'mem': 0
};
if (proc) {
if (_windows) {
try {
util.wmic('process get /value').then((stdout, error) => {
if (!error) {
let processSections = stdout.split(/\n\s*\n/);
let procStats = [];
let list_new = {};
let allcpuu = 0;
let allcpus = 0;
for (let i = 0; i < processSections.length; i++) {
if (processSections[i].trim() !== '') {
let lines = processSections[i].trim().split('\r\n');
let pid = parseInt(util.getValue(lines, 'ProcessId', '=', true), 10);
let name = util.getValue(lines, 'Caption', '=', true);
let utime = parseInt(util.getValue(lines, 'UserModeTime', '=', true), 10);
let stime = parseInt(util.getValue(lines, 'KernelModeTime', '=', true), 10);
let mem = parseInt(util.getValue(lines, 'WorkingSetSize', '=', true), 10);
allcpuu = allcpuu + utime;
allcpus = allcpus + stime;
procStats.push({
pid: pid,
utime: utime,
stime: stime,
pcpu: 0,
pcpuu: 0,
pcpus: 0,
});
if (name.toLowerCase().indexOf(proc.toLowerCase()) >= 0) {
if (result.pid === -1) {
result = {
proc: name,
pid: pid,
pids: [pid],
cpu: 0,
mem: mem / os.totalmem() * 100
};
} else {
result.pids.push(pid);
result.mem += mem / os.totalmem() * 100;
}
}
}
}
for (let i = 0; i < procStats.length; i++) {
let resultProcess = calcProcStatWin(procStats[i], allcpuu + allcpus, _process_cpu);
// store pcpu in outer array
if (result && result.pids && result.pids.length > 0) {
let listPos = result.pids.indexOf(resultProcess.pid);
if (listPos >= 0) {
result.cpu = resultProcess.pcpuu + resultProcess.pcpus;
}
}
// save new values
list_new[resultProcess.pid] = {
pcpuu: resultProcess.pcpuu,
pcpus: resultProcess.pcpus,
utime: resultProcess.utime,
stime: resultProcess.stime
};
}
// store old values
_process_cpu.all = allcpuu + allcpus;
_process_cpu.list = list_new;
_process_cpu.ms = Date.now() - _process_cpu.ms;
_process_cpu.result = result;
if (callback) {
callback(result);
}
resolve(result);
}
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
if (_darwin || _linux) {
exec('ps -axo pid,pcpu,pmem,comm | grep -i ' + proc + ' | grep -v grep', { maxBuffer: 1024 * 20000 }, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
let pid = 0;
let pids = [];
let cpu = 0;
let mem = 0;
lines.forEach(function (line) {
let data = line.trim().replace(/ +/g, ' ').split(' ');
if (data.length > 3) {
pid = (!pid ? parseInt(data[0]) : 0);
pids.push(parseInt(data[0], 10));
cpu = cpu + parseFloat(data[1].replace(',', '.'));
mem = mem + parseFloat(data[2].replace(',', '.'));
}
});
result = {
'proc': proc,
'pid': pid,
'pids': pids,
'cpu': parseFloat((cpu / lines.length).toFixed(2)),
'mem': parseFloat((mem / lines.length).toFixed(2))
};
if (_linux) {
// calc process_cpu - ps is not accurate in linux!
let cmd = 'cat /proc/stat | grep "cpu "';
for (let i = 0; i < result.pids.length; i++) {
cmd += (';cat /proc/' + result.pids[i] + '/stat');
}
exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
let curr_processes = stdout.toString().split('\n');
// first line (all - /proc/stat)
let all = parseProcStat(curr_processes.shift());
// process
let list_new = {};
let resultProcess = {};
result.cpu = 0;
for (let i = 0; i < curr_processes.length; i++) {
resultProcess = calcProcStatLinux(curr_processes[i], all, _process_cpu);
if (resultProcess.pid) {
// store pcpu in outer result
result.cpu += resultProcess.pcpuu + resultProcess.pcpus;
// save new values
list_new[resultProcess.pid] = {
pcpuu: resultProcess.pcpuu,
pcpus: resultProcess.pcpus,
utime: resultProcess.utime,
stime: resultProcess.stime,
cutime: resultProcess.cutime,
cstime: resultProcess.cstime
};
}
}
result.cpu = Math.round(result.cpu * 100) / 100;
_process_cpu.all = all;
_process_cpu.list = list_new;
_process_cpu.ms = Date.now() - _process_cpu.ms;
_process_cpu.result = result;
if (callback) { callback(result); }
resolve(result);
});
} else {
if (callback) { callback(result); }
resolve(result);
}
} else {
if (callback) { callback(result); }
resolve(result);
}
});
}
}
});
});
}
exports.processLoad = processLoad;
'use strict';
// @ts-check
// ==================================================================================
// system.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 2. System (Hardware, BIOS, Base Board)
// ----------------------------------------------------------------------------------
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;
const fs = require('fs');
const util = require('./util');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
function system(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
manufacturer: '',
model: 'Computer',
version: '',
serial: '-',
uuid: '-',
sku: '-',
};
if (_linux || _freebsd || _openbsd || _netbsd) {
exec('export LC_ALL=C; dmidecode -t system 2>/dev/null; unset LC_ALL', function (error, stdout) {
// if (!error) {
let lines = stdout.toString().split('\n');
result.manufacturer = util.getValue(lines, 'manufacturer');
result.model = util.getValue(lines, 'product name');
result.version = util.getValue(lines, 'version');
result.serial = util.getValue(lines, 'serial number');
result.uuid = util.getValue(lines, 'uuid');
result.sku = util.getValue(lines, 'sku number');
// }
// Non-Root values
const cmd = `echo -n "product_name: "; cat /sys/devices/virtual/dmi/id/product_name 2>/dev/null; echo;
echo -n "product_serial: "; cat /sys/devices/virtual/dmi/id/product_serial 2>/dev/null; echo;
echo -n "product_uuid: "; cat /sys/devices/virtual/dmi/id/product_uuid 2>/dev/null; echo;
echo -n "product_version: "; cat /sys/devices/virtual/dmi/id/product_version 2>/dev/null; echo;
echo -n "sys_vendor: "; cat /sys/devices/virtual/dmi/id/sys_vendor 2>/dev/null; echo;`;
try {
lines = execSync(cmd).toString().split('\n');
result.manufacturer = result.manufacturer === '' ? util.getValue(lines, 'sys_vendor') : result.manufacturer;
result.model = result.model === '' ? util.getValue(lines, 'product_name') : result.model;
result.version = result.version === '' ? util.getValue(lines, 'product_version') : result.version;
result.serial = result.serial === '' ? util.getValue(lines, 'product_serial') : result.serial;
result.uuid = result.uuid === '' ? util.getValue(lines, 'product_uuid') : result.uuid;
} catch (e) {
util.noop();
}
if (!result.serial || result.serial.toLowerCase().indexOf('o.e.m.') !== -1) result.serial = '-';
if (!result.manufacturer || result.manufacturer.toLowerCase().indexOf('o.e.m.') !== -1) result.manufacturer = '';
if (!result.model || result.model.toLowerCase().indexOf('o.e.m.') !== -1) result.model = 'Computer';
if (!result.version || result.version.toLowerCase().indexOf('o.e.m.') !== -1) result.version = '';
if (!result.sku || result.sku.toLowerCase().indexOf('o.e.m.') !== -1) result.sku = '-';
// detect docker
if (fs.existsSync('/.dockerenv') || fs.existsSync('/.dockerinit')) {
result.model = 'Docker Container';
}
if (result.manufacturer === '' && result.model === 'Computer' && result.version === '') { // still default values
exec('dmesg | grep -i virtual | grep -iE "vmware|qemu|kvm|xen"', function (error, stdout) {
// detect virtual machines
if (!error) {
let lines = stdout.toString().split('\n');
if (lines.length > 0) result.model = 'Virtual machine';
}
if (result.manufacturer === '' && result.model === 'Computer' && result.version === '') {
// Check Raspberry Pi
exec('cat /proc/cpuinfo', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result.model = util.getValue(lines, 'hardware', ':', true).toUpperCase();
result.version = util.getValue(lines, 'revision', ':', true).toLowerCase();
result.serial = util.getValue(lines, 'serial', ':', true);
// reference values: https://elinux.org/RPi_HardwareHistory
// https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
if (result.model === 'BCM2835' || result.model === 'BCM2708' || result.model === 'BCM2709' || result.model === 'BCM2835' || result.model === 'BCM2837') {
// Pi 4
if (['a03111', 'b03111', 'c03111'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi 4 Model B';
result.version = result.version + ' - Rev. 1.1';
}
// Pi 3
if (['a02082', 'a22082', 'a32082'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi 3 Model B';
result.version = result.version + ' - Rev. 1.2';
}
if (['a020d3'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi 3 Model B+';
result.version = result.version + ' - Rev. 1.3';
}
if (['9020e0'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi 3 Model A+';
result.version = result.version + ' - Rev. 1.3';
}
// Pi 2 Model B
if (['a01040'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi 2 Model B';
result.version = result.version + ' - Rev. 1.0';
}
if (['a01041', 'a21041'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi 2 Model B';
result.version = result.version + ' - Rev. 1.1';
}
if (['a22042'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi 2 Model B';
result.version = result.version + ' - Rev. 1.2';
}
// Pi Zero
if (['900092'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi Zero';
result.version = result.version + ' - Rev 1.2';
}
if (['900093', '920093'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi Zero';
result.version = result.version + ' - Rev 1.3';
}
if (['9000c1'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi Zero W';
result.version = result.version + ' - Rev 1.1';
}
// A, B, A+ B+
if (['0002', '0003'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi Model B';
result.version = result.version + ' - Rev 1.0';
}
if (['0004', '0005', '0006', '000d', '000e', '000f'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi Model B';
result.version = result.version + ' - Rev 2.0';
}
if (['0007', '0008', '0009'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi Model A';
result.version = result.version + ' - Rev 2.0';
}
if (['0010'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi Model B+';
result.version = result.version + ' - Rev 1.0';
}
if (['0012'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi Model A+';
result.version = result.version + ' - Rev 1.0';
}
if (['0013'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi Model B+';
result.version = result.version + ' - Rev 1.2';
}
if (['0015'].indexOf(result.version) >= 0) {
result.model = result.model + ' - Pi Model A+';
result.version = result.version + ' - Rev 1.1';
}
if (result.model.indexOf('Pi') !== -1 && result.version) { // Pi, Pi Zero
result.manufacturer = 'Raspberry Pi Foundation';
}
}
}
if (callback) { callback(result); }
resolve(result);
});
} else {
if (callback) { callback(result); }
resolve(result);
}
});
} else {
if (callback) { callback(result); }
resolve(result);
}
});
}
if (_darwin) {
exec('ioreg -c IOPlatformExpertDevice -d 2', function (error, stdout) {
if (!error) {
let lines = stdout.toString().replace(/[<>"]/g, '').split('\n');
result.manufacturer = util.getValue(lines, 'manufacturer', '=', true);
result.model = util.getValue(lines, 'model', '=', true);
result.version = util.getValue(lines, 'version', '=', true);
result.serial = util.getValue(lines, 'ioplatformserialnumber', '=', true);
result.uuid = util.getValue(lines, 'ioplatformuuid', '=', true);
result.sku = util.getValue(lines, 'board-id', '=', true);
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_sunos) {
if (callback) { callback(result); }
resolve(result);
}
if (_windows) {
try {
util.wmic('csproduct get /value').then((stdout, error) => {
if (!error) {
// let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0)[0].trim().split(/\s\s+/);
let lines = stdout.split('\r\n');
result.manufacturer = util.getValue(lines, 'vendor', '=');
result.model = util.getValue(lines, 'name', '=');
result.version = util.getValue(lines, 'version', '=');
result.serial = util.getValue(lines, 'identifyingnumber', '=');
result.uuid = util.getValue(lines, 'uuid', '=');
util.wmic('/namespace:\\\\root\\wmi path MS_SystemInformation get /value').then((stdout, error) => {
if (!error) {
let lines = stdout.split('\r\n');
result.sku = util.getValue(lines, 'systemsku', '=');
}
if (callback) { callback(result); }
resolve(result);
});
} else {
if (callback) { callback(result); }
resolve(result);
}
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.system = system;
function bios(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
vendor: '',
version: '',
releaseDate: '',
revision: '',
};
let cmd = '';
if (_linux || _freebsd || _openbsd || _netbsd) {
if (process.arch === 'arm') {
cmd = 'cat /proc/cpuinfo | grep Serial';
} else {
cmd = 'export LC_ALL=C; dmidecode --type 0 2>/dev/null; unset LC_ALL';
}
exec(cmd, function (error, stdout) {
let lines = stdout.toString().split('\n');
result.vendor = util.getValue(lines, 'Vendor');
result.version = util.getValue(lines, 'Version');
let datetime = util.getValue(lines, 'Release Date');
result.releaseDate = util.parseDateTime(datetime).date;
result.revision = util.getValue(lines, 'BIOS Revision');
// Non-Root values
const cmd = `echo -n "bios_date: "; cat /sys/devices/virtual/dmi/id/bios_date 2>/dev/null; echo;
echo -n "bios_vendor: "; cat /sys/devices/virtual/dmi/id/bios_vendor 2>/dev/null; echo;
echo -n "bios_version: "; cat /sys/devices/virtual/dmi/id/bios_version 2>/dev/null; echo;`;
try {
lines = execSync(cmd).toString().split('\n');
result.vendor = !result.vendor ? util.getValue(lines, 'bios_vendor') : result.vendor;
result.version = !result.version ? util.getValue(lines, 'bios_version') : result.version;
datetime = util.getValue(lines, 'bios_date');
result.releaseDate = !result.releaseDate ? util.parseDateTime(datetime).date : result.releaseDate;
} catch (e) {
util.noop();
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_darwin) {
result.vendor = 'Apple Inc.';
if (callback) { callback(result); }
resolve(result);
}
if (_sunos) {
result.vendor = 'Sun Microsystems';
if (callback) { callback(result); }
resolve(result);
}
if (_windows) {
try {
util.wmic('bios get /value').then((stdout, error) => {
if (!error) {
let lines = stdout.toString().split('\r\n');
const description = util.getValue(lines, 'description', '=');
if (description.indexOf(' Version ') !== -1) {
// ... Phoenix ROM BIOS PLUS Version 1.10 A04
result.vendor = description.split(' Version ')[0].trim();
result.version = description.split(' Version ')[1].trim();
} else if (description.indexOf(' Ver: ') !== -1) {
// ... BIOS Date: 06/27/16 17:50:16 Ver: 1.4.5
result.vendor = util.getValue(lines, 'manufacturer', '=');
result.version = description.split(' Ver: ')[1].trim();
} else {
result.vendor = util.getValue(lines, 'manufacturer', '=');
result.version = util.getValue(lines, 'version', '=');
}
result.releaseDate = util.getValue(lines, 'releasedate', '=');
if (result.releaseDate.length >= 10) {
result.releaseDate = result.releaseDate.substr(0, 4) + '-' + result.releaseDate.substr(4, 2) + '-' + result.releaseDate.substr(6, 2);
}
result.revision = util.getValue(lines, 'buildnumber', '=');
}
if (callback) { callback(result); }
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.bios = bios;
function baseboard(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
manufacturer: '',
model: '',
version: '',
serial: '-',
assetTag: '-',
};
let cmd = '';
if (_linux || _freebsd || _openbsd || _netbsd) {
if (process.arch === 'arm') {
cmd = 'cat /proc/cpuinfo | grep Serial';
// 'BCM2709', 'BCM2835', 'BCM2708' -->
} else {
cmd = 'export LC_ALL=C; dmidecode -t 2 2>/dev/null; unset LC_ALL';
}
exec(cmd, function (error, stdout) {
let lines = stdout.toString().split('\n');
result.manufacturer = util.getValue(lines, 'Manufacturer');
result.model = util.getValue(lines, 'Product Name');
result.version = util.getValue(lines, 'Version');
result.serial = util.getValue(lines, 'Serial Number');
result.assetTag = util.getValue(lines, 'Asset Tag');
// Non-Root values
const cmd = `echo -n "board_asset_tag: "; cat /sys/devices/virtual/dmi/id/board_asset_tag 2>/dev/null; echo;
echo -n "board_name: "; cat /sys/devices/virtual/dmi/id/board_name 2>/dev/null; echo;
echo -n "board_serial: "; cat /sys/devices/virtual/dmi/id/board_serial 2>/dev/null; echo;
echo -n "board_vendor: "; cat /sys/devices/virtual/dmi/id/board_vendor 2>/dev/null; echo;
echo -n "board_version: "; cat /sys/devices/virtual/dmi/id/board_version 2>/dev/null; echo;`;
try {
lines = execSync(cmd).toString().split('\n');
result.manufacturer = !result.manufacturer ? util.getValue(lines, 'board_vendor') : result.manufacturer;
result.model = !result.model ? util.getValue(lines, 'board_name') : result.model;
result.version = !result.version ? util.getValue(lines, 'board_version') : result.version;
result.serial = !result.serial ? util.getValue(lines, 'board_serial') : result.serial;
result.assetTag = !result.assetTag ? util.getValue(lines, 'board_asset_tag') : result.assetTag;
} catch (e) {
util.noop();
}
if (result.serial.toLowerCase().indexOf('o.e.m.') !== -1) result.serial = '-';
if (result.assetTag.toLowerCase().indexOf('o.e.m.') !== -1) result.assetTag = '-';
if (callback) { callback(result); }
resolve(result);
});
}
if (_darwin) {
exec('ioreg -c IOPlatformExpertDevice -d 2', function (error, stdout) {
if (!error) {
let lines = stdout.toString().replace(/[<>"]/g, '').split('\n');
result.manufacturer = util.getValue(lines, 'manufacturer', '=', true);
result.model = util.getValue(lines, 'model', '=', true);
result.version = util.getValue(lines, 'version', '=', true);
result.serial = util.getValue(lines, 'ioplatformserialnumber', '=', true);
result.assetTag = util.getValue(lines, 'board-id', '=', true);
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_sunos) {
if (callback) { callback(result); }
resolve(result);
}
if (_windows) {
try {
util.wmic('baseboard get /value').then((stdout, error) => {
if (!error) {
let lines = stdout.toString().split('\r\n');
result.manufacturer = util.getValue(lines, 'manufacturer', '=');
result.model = util.getValue(lines, 'model', '=');
if (!result.model) {
result.model = util.getValue(lines, 'product', '=');
}
result.version = util.getValue(lines, 'version', '=');
result.serial = util.getValue(lines, 'serialnumber', '=');
result.assetTag = util.getValue(lines, 'partnumber', '=');
if (!result.assetTag) {
result.assetTag = util.getValue(lines, 'sku', '=');
}
}
if (callback) { callback(result); }
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.baseboard = baseboard;
function chassis(callback) {
const chassisTypes = ['Other',
'Unknown',
'Desktop',
'Low Profile Desktop',
'Pizza Box',
'Mini Tower',
'Tower',
'Portable',
'Laptop',
'Notebook',
'Hand Held',
'Docking Station',
'All in One',
'Sub Notebook',
'Space-Saving',
'Lunch Box',
'Main System Chassis',
'Expansion Chassis',
'SubChassis',
'Bus Expansion Chassis',
'Peripheral Chassis',
'Storage Chassis',
'Rack Mount Chassis',
'Sealed-Case PC',
'Multi-System Chassis',
'Compact PCI',
'Advanced TCA',
'Blade',
'Blade Enclosure',
'Tablet',
'Concertible',
'Detachable',
'IoT Gateway ',
'Embedded PC',
'Mini PC',
'Stick PC',
];
return new Promise((resolve) => {
process.nextTick(() => {
let result = {
manufacturer: '',
model: '',
type: '',
version: '',
serial: '-',
assetTag: '-',
sku: '',
};
if (_linux || _freebsd || _openbsd || _netbsd) {
const cmd = `echo -n "chassis_asset_tag: "; cat /sys/devices/virtual/dmi/id/chassis_asset_tag 2>/dev/null; echo;
echo -n "chassis_serial: "; cat /sys/devices/virtual/dmi/id/chassis_serial 2>/dev/null; echo;
echo -n "chassis_type: "; cat /sys/devices/virtual/dmi/id/chassis_type 2>/dev/null; echo;
echo -n "chassis_vendor: "; cat /sys/devices/virtual/dmi/id/chassis_vendor 2>/dev/null; echo;
echo -n "chassis_version: "; cat /sys/devices/virtual/dmi/id/chassis_version 2>/dev/null; echo;`;
exec(cmd, function (error, stdout) {
let lines = stdout.toString().split('\n');
result.manufacturer = util.getValue(lines, 'chassis_vendor');
const ctype = parseInt(util.getValue(lines, 'chassis_type').replace(/\D/g, ''));
result.type = (ctype && !isNaN(ctype) && ctype < chassisTypes.length) ? chassisTypes[ctype - 1] : '';
result.version = util.getValue(lines, 'chassis_version');
result.serial = util.getValue(lines, 'chassis_serial');
result.assetTag = util.getValue(lines, 'chassis_asset_tag');
if (result.serial.toLowerCase().indexOf('o.e.m.') !== -1) result.serial = '-';
if (result.assetTag.toLowerCase().indexOf('o.e.m.') !== -1) result.assetTag = '-';
if (callback) { callback(result); }
resolve(result);
});
}
if (_darwin) {
exec('ioreg -c IOPlatformExpertDevice -d 2', function (error, stdout) {
if (!error) {
let lines = stdout.toString().replace(/[<>"]/g, '').split('\n');
result.manufacturer = util.getValue(lines, 'manufacturer', '=', true);
result.model = util.getValue(lines, 'model', '=', true);
result.version = util.getValue(lines, 'version', '=', true);
result.serial = util.getValue(lines, 'ioplatformserialnumber', '=', true);
result.assetTag = util.getValue(lines, 'board-id', '=', true);
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_sunos) {
if (callback) { callback(result); }
resolve(result);
}
if (_windows) {
try {
util.wmic('path Win32_SystemEnclosure get /value').then((stdout, error) => {
if (!error) {
let lines = stdout.toString().split('\r\n');
result.manufacturer = util.getValue(lines, 'manufacturer', '=');
result.model = util.getValue(lines, 'model', '=');
const ctype = parseInt(util.getValue(lines, 'ChassisTypes', '=').replace(/\D/g, ''));
result.type = (ctype && !isNaN(ctype) && ctype < chassisTypes.length) ? chassisTypes[ctype - 1] : '';
result.version = util.getValue(lines, 'version', '=');
result.serial = util.getValue(lines, 'serialnumber', '=');
result.assetTag = util.getValue(lines, 'partnumber', '=');
result.sku = util.getValue(lines, 'sku', '=');
}
if (callback) { callback(result); }
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.chassis = chassis;
'use strict';
// @ts-check
// ==================================================================================
// users.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 11. Users/Sessions
// ----------------------------------------------------------------------------------
const exec = require('child_process').exec;
const util = require('./util');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
// --------------------------
// array of users online = sessions
function parseUsersLinux(lines, phase) {
let result = [];
let result_who = [];
let result_w = {};
let w_first = true;
let w_header = [];
let w_pos = [];
let who_line = {};
let is_whopart = true;
lines.forEach(function (line) {
if (line === '---') {
is_whopart = false;
} else {
let l = line.replace(/ +/g, ' ').split(' ');
// who part
if (is_whopart) {
result_who.push({
user: l[0],
tty: l[1],
date: l[2],
time: l[3],
ip: (l && l.length > 4) ? l[4].replace(/\(/g, '').replace(/\)/g, '') : ''
});
} else {
// w part
if (w_first) { // header
w_header = l;
w_header.forEach(function (item) {
w_pos.push(line.indexOf(item));
});
w_first = false;
} else {
// split by w_pos
result_w.user = line.substring(w_pos[0], w_pos[1] - 1).trim();
result_w.tty = line.substring(w_pos[1], w_pos[2] - 1).trim();
result_w.ip = line.substring(w_pos[2], w_pos[3] - 1).replace(/\(/g, '').replace(/\)/g, '').trim();
result_w.command = line.substring(w_pos[7], 1000).trim();
// find corresponding 'who' line
who_line = result_who.filter(function (obj) {
return (obj.user.substring(0, 8).trim() === result_w.user && obj.tty === result_w.tty);
});
if (who_line.length === 1) {
result.push({
user: who_line[0].user,
tty: who_line[0].tty,
date: who_line[0].date,
time: who_line[0].time,
ip: who_line[0].ip,
command: result_w.command
});
}
}
}
}
});
if (result.length === 0 && phase === 2) {
return result_who;
} else {
return result;
}
}
function parseUsersDarwin(lines) {
let result = [];
let result_who = [];
let result_w = {};
let who_line = {};
let is_whopart = true;
lines.forEach(function (line) {
if (line === '---') {
is_whopart = false;
} else {
let l = line.replace(/ +/g, ' ').split(' ');
// who part
if (is_whopart) {
result_who.push({
user: l[0],
tty: l[1],
date: ('' + new Date().getFullYear()) + '-' + ('0' + ('JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'.indexOf(l[2].toUpperCase()) / 3 + 1)).slice(-2) + '-' + ('0' + l[3]).slice(-2),
time: l[4],
});
} else {
// w part
// split by w_pos
result_w.user = l[0];
result_w.tty = l[1];
result_w.ip = (l[2] !== '-') ? l[2] : '';
result_w.command = l.slice(5, 1000).join(' ');
// find corresponding 'who' line
who_line = result_who.filter(function (obj) {
return (obj.user === result_w.user && (obj.tty.substring(3, 1000) === result_w.tty || obj.tty === result_w.tty));
});
if (who_line.length === 1) {
result.push({
user: who_line[0].user,
tty: who_line[0].tty,
date: who_line[0].date,
time: who_line[0].time,
ip: result_w.ip,
command: result_w.command
});
}
}
}
});
return result;
}
function parseUsersWin(lines) {
let result = [];
const header = lines[0];
const headerDelimiter = [];
if (header) {
const start = (header[0] === ' ') ? 1 : 0;
headerDelimiter.push(start - 1);
let nextSpace = 0;
for (let i = start + 1; i < header.length; i++) {
if (header[i] === ' ' && ((header[i - 1] === ' ') || (header[i - 1] === '.'))) {
nextSpace = i;
} else {
if (nextSpace) {
headerDelimiter.push(nextSpace);
nextSpace = 0;
}
}
}
for (let i = 1; i < lines.length; i++) {
if (lines[i].trim()) {
const user = lines[i].substring(headerDelimiter[0] + 1, headerDelimiter[1]).trim() || '';
const tty = lines[i].substring(headerDelimiter[1] + 1, headerDelimiter[2] - 2).trim() || '';
const dateTime = util.parseDateTime(lines[i].substring(headerDelimiter[5] + 1, 2000).trim()) || '';
result.push({
user: user,
tty: tty,
date: dateTime.date,
time: dateTime.time,
ip: '',
command: ''
});
}
}
}
return result;
}
function users(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = [];
// linux
if (_linux) {
exec('who --ips; echo "---"; w | tail -n +2', function (error, stdout) {
if (!error) {
// lines / split
let lines = stdout.toString().split('\n');
result = parseUsersLinux(lines, 1);
if (result.length === 0) {
exec('who; echo "---"; w | tail -n +2', function (error, stdout) {
if (!error) {
// lines / split
lines = stdout.toString().split('\n');
result = parseUsersLinux(lines, 2);
}
if (callback) { callback(result); }
resolve(result);
});
} else {
if (callback) { callback(result); }
resolve(result);
}
} else {
if (callback) { callback(result); }
resolve(result);
}
});
}
if (_freebsd || _openbsd || _netbsd) {
exec('who; echo "---"; w -ih', function (error, stdout) {
if (!error) {
// lines / split
let lines = stdout.toString().split('\n');
result = parseUsersDarwin(lines);
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_sunos) {
exec('who; echo "---"; w -h', function (error, stdout) {
if (!error) {
// lines / split
let lines = stdout.toString().split('\n');
result = parseUsersDarwin(lines);
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_darwin) {
exec('who; echo "---"; w -ih', function (error, stdout) {
if (!error) {
// lines / split
let lines = stdout.toString().split('\n');
result = parseUsersDarwin(lines);
}
if (callback) { callback(result); }
resolve(result);
});
}
if (_windows) {
try {
exec('query user', util.execOptsWin, function (error, stdout) {
if (stdout) {
// lines / split
let lines = stdout.toString().split('\r\n');
result = parseUsersWin(lines);
}
if (callback) { callback(result); }
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
}
});
});
}
exports.users = users;
'use strict';
// @ts-check
// ==================================================================================
// utils.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 0. helper functions
// ----------------------------------------------------------------------------------
const os = require('os');
const fs = require('fs');
const spawn = require('child_process').spawn;
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;
const util = require('util');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
// const _sunos = (_platform === 'sunos');
let _cores = 0;
let wmicPath = '';
let codepage = '';
const execOptsWin = {
windowsHide: true,
maxBuffer: 1024 * 20000,
encoding: 'UTF-8',
env: util._extend({}, process.env, { LANG: 'en_US.UTF-8' })
};
function toInt(value) {
let result = parseInt(value, 10);
if (isNaN(result)) {
result = 0;
}
return result;
}
function isFunction(functionToCheck) {
let getType = {};
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
}
function unique(obj) {
let uniques = [];
let stringify = {};
for (let i = 0; i < obj.length; i++) {
let keys = Object.keys(obj[i]);
keys.sort(function (a, b) { return a - b; });
let str = '';
for (let j = 0; j < keys.length; j++) {
str += JSON.stringify(keys[j]);
str += JSON.stringify(obj[i][keys[j]]);
}
if (!stringify.hasOwnProperty(str)) {
uniques.push(obj[i]);
stringify[str] = true;
}
}
return uniques;
}
function sortByKey(array, keys) {
return array.sort(function (a, b) {
let x = '';
let y = '';
keys.forEach(function (key) {
x = x + a[key]; y = y + b[key];
});
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
}
function cores() {
if (_cores === 0) {
_cores = os.cpus().length;
}
return _cores;
}
function getValue(lines, property, separator, trimmed) {
separator = separator || ':';
property = property.toLowerCase();
trimmed = trimmed || false;
for (let i = 0; i < lines.length; i++) {
let line = lines[i].toLowerCase().replace(/\t/g, '');
if (trimmed) {
line = line.trim();
}
if (line.startsWith(property)) {
const parts = lines[i].split(separator);
if (parts.length >= 2) {
parts.shift();
return parts.join(separator).trim();
} else {
return '';
}
}
}
return '';
}
function decodeEscapeSequence(str, base) {
base = base || 16;
return str.replace(/\\x([0-9A-Fa-f]{2})/g, function () {
return String.fromCharCode(parseInt(arguments[1], base));
});
}
function parseTime(t) {
t = t.toUpperCase();
let hour = 0;
let min = 0;
let parts = t.split(':');
if (parts.length >= 2) {
let isPM = (parts[1] && (parts[1].toLowerCase().indexOf('pm') > -1) || (parts[1].toLowerCase().indexOf('p.m.') > -1) || (parts[1].toLowerCase().indexOf('p. m.') > -1));
hour = parseInt(parts[0], 10);
min = parseInt(parts[1], 10);
hour = isPM && hour < 12 ? hour + 12 : hour;
return ('0' + hour).substr(-2) + ':' + ('0' + min).substr(-2);
}
parts = t.split('.');
if (parts.length >= 2) {
let isPM = (parts[1] && (parts[1].toLowerCase().indexOf('pm') > -1) || (parts[1].toLowerCase().indexOf('p.m.') > -1) || (parts[1].toLowerCase().indexOf('p. m.') > -1) || (parts[1].toLowerCase().indexOf('n') > -1) || (parts[1].toLowerCase().indexOf('ch') > -1) || (parts[1].toLowerCase().indexOf('ös') > -1));
hour = parseInt(parts[0], 10);
min = parseInt(parts[1], 10);
hour = isPM && hour < 12 ? hour + 12 : hour;
return ('0' + hour).substr(-2) + ':' + ('0' + min).substr(-2);
}
parts = t.split(' ');
if (parts.length >= 2) {
let isPM = ((t.toLowerCase().indexOf('pm') > -1) || (t.toLowerCase().indexOf('p.m.') > -1) || (t.toLowerCase().indexOf('p. m.') > -1) || (t.toLowerCase().indexOf('n') > -1) || (t.toLowerCase().indexOf('ch') > -1) || (t.toLowerCase().indexOf('ös') > -1));
hour = parseInt(parts[0], 10);
if (parts[1] === 'h' && parts[2]) {
min = parseInt(parts[2], 10);
} else {
min = parseInt(parts[1], 10);
}
hour = isPM && hour < 12 ? hour + 12 : hour;
return ('0' + hour).substr(-2) + ':' + ('0' + min).substr(-2);
}
}
function parseDateTime(dt) {
const result = {
date: '',
time: ''
};
const parts = dt.split(' ');
if (parts[0]) {
if (parts[0].indexOf('/') >= 0) {
// Dateformat: mm/dd/yyyy or dd/mm/yyyy or dd/mm/yy or yyyy/mm/dd
const dtparts = parts[0].split('/');
if (dtparts.length === 3) {
if (dtparts[0].length === 4) {
// Dateformat: yyyy/mm/dd
result.date = dtparts[0] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[2]).substr(-2);
} else if (dtparts[2].length === 2) {
// Dateformat: dd/mm/yy
result.date = '20' + dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
} else {
// Dateformat: mm/dd/yyyy or dd/mm/yyyy
const isEN = ((dt.toLowerCase().indexOf('pm') > -1) || (dt.toLowerCase().indexOf('p.m.') > -1) || (dt.toLowerCase().indexOf('p. m.') > -1) || (dt.toLowerCase().indexOf('am') > -1) || (dt.toLowerCase().indexOf('a.m.') > -1) || (dt.toLowerCase().indexOf('a. m.') > -1));
if (isEN) {
// Dateformat: mm/dd/yyyy
result.date = dtparts[2] + '-' + ('0' + dtparts[0]).substr(-2) + '-' + ('0' + dtparts[1]).substr(-2);
} else {
// Dateformat: dd/mm/yyyy
result.date = dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
}
}
}
}
if (parts[0].indexOf('.') >= 0) {
// Dateformat: dd.mm.yyyy
const dtparts = parts[0].split('.');
if (dtparts.length === 3) {
result.date = dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
}
}
if (parts[0].indexOf('-') >= 0) {
// Dateformat: yyyy-mm-dd
const dtparts = parts[0].split('-');
if (dtparts.length === 3) {
result.date = dtparts[0] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[2]).substr(-2);
}
}
}
if (parts[1]) {
parts.shift();
let time = parts.join(' ');
result.time = parseTime(time);
}
return result;
}
function parseHead(head, rights) {
let space = (rights > 0);
let count = 1;
let from = 0;
let to = 0;
let result = [];
for (let i = 0; i < head.length; i++) {
if (count <= rights) {
// if (head[i] === ' ' && !space) {
if (/\s/.test(head[i]) && !space) {
to = i - 1;
result.push({
from: from,
to: to + 1,
cap: head.substring(from, to + 1)
});
from = to + 2;
count++;
}
space = head[i] === ' ';
} else {
if (!/\s/.test(head[i]) && space) {
to = i - 1;
if (from < to) {
result.push({
from: from,
to: to,
cap: head.substring(from, to)
});
}
from = to + 1;
count++;
}
space = head[i] === ' ';
}
}
to = 1000;
result.push({
from: from,
to: to,
cap: head.substring(from, to)
});
let len = result.length;
for (var i = 0; i < len; i++) {
if (result[i].cap.replace(/\s/g, '').length === 0) {
if (i + 1 < len) {
result[i].to = result[i + 1].to;
result[i].cap = result[i].cap + result[i + 1].cap;
result.splice(i + 1, 1);
len = len - 1;
}
}
}
return result;
}
function findObjectByKey(array, key, value) {
for (let i = 0; i < array.length; i++) {
if (array[i][key] === value) {
return i;
}
}
return -1;
}
function getWmic() {
if (os.type() === 'Windows_NT' && !wmicPath) {
wmicPath = process.env.WINDIR + '\\system32\\wbem\\wmic.exe';
if (!fs.existsSync(wmicPath)) {
try {
const wmicPathArray = execSync('WHERE WMIC').toString().split('\r\n');
if (wmicPathArray && wmicPathArray.length) {
wmicPath = wmicPathArray[0];
} else {
wmicPath = 'wmic';
}
} catch (e) {
wmicPath = 'wmic';
}
}
}
return wmicPath;
}
function wmic(command, options) {
options = options || execOptsWin;
return new Promise((resolve) => {
process.nextTick(() => {
try {
exec(getWmic() + ' ' + command, options, function (error, stdout) {
resolve(stdout, error);
}).stdin.end();
} catch (e) {
resolve('', e);
}
});
});
}
function getVboxmanage() {
return _windows ? process.env.VBOX_INSTALL_PATH || process.env.VBOX_MSI_INSTALL_PATH + '\\VBoxManage.exe' + '" ' : 'vboxmanage';
}
function powerShell(cmd) {
let result = '';
return new Promise((resolve) => {
process.nextTick(() => {
try {
const child = spawn('powershell.exe', ['-NoLogo', '-InputFormat', 'Text', '-NoExit', '-ExecutionPolicy', 'Unrestricted', '-Command', '-'], {
stdio: 'pipe'
});
if (child && child.pid) {
child.stdout.on('data', function (data) {
result = result + data.toString('utf8');
});
child.stderr.on('data', function () {
child.kill();
resolve(result);
});
child.on('close', function () {
child.kill();
resolve(result);
});
child.on('error', function () {
child.kill();
resolve(result);
});
try {
child.stdin.write(cmd + os.EOL);
child.stdin.write('exit' + os.EOL);
child.stdin.end();
} catch (e) {
child.kill();
resolve(result);
}
} else {
resolve(result);
}
} catch (e) {
resolve(result);
}
});
});
}
function getCodepage() {
if (_windows) {
if (!codepage) {
try {
const stdout = execSync('chcp');
const lines = stdout.toString().split('\r\n');
const parts = lines[0].split(':');
codepage = parts.length > 1 ? parts[1].replace('.', '') : '';
} catch (err) {
codepage = '437';
}
}
return codepage;
}
if (_linux || _darwin || _freebsd || _openbsd || _netbsd) {
if (!codepage) {
try {
const stdout = execSync('echo $LANG');
const lines = stdout.toString().split('\r\n');
const parts = lines[0].split('.');
codepage = parts.length > 1 ? parts[1].trim() : '';
if (!codepage) {
codepage = 'UTF-8';
}
} catch (err) {
codepage = 'UTF-8';
}
}
return codepage;
}
}
function isRaspberry() {
const PI_MODEL_NO = [
'BCM2708',
'BCM2709',
'BCM2710',
'BCM2835',
'BCM2837B0'
];
let cpuinfo = [];
try {
cpuinfo = fs.readFileSync('/proc/cpuinfo', { encoding: 'utf8' }).split('\n');
} catch (e) {
return false;
}
const hardware = getValue(cpuinfo, 'hardware');
return (hardware && PI_MODEL_NO.indexOf(hardware) > -1);
}
function isRaspbian() {
let osrelease = [];
try {
osrelease = fs.readFileSync('/etc/os-release', { encoding: 'utf8' }).split('\n');
} catch (e) {
return false;
}
const id = getValue(osrelease, 'id');
return (id && id.indexOf('raspbian') > -1);
}
function execWin(cmd, opts, callback) {
if (!callback) {
callback = opts;
opts = execOptsWin;
}
let newCmd = 'chcp 65001 > nul && cmd /C ' + cmd + ' && chcp ' + codepage + ' > nul';
exec(newCmd, opts, function (error, stdout) {
callback(error, stdout);
});
}
function darwinXcodeExists() {
const cmdLineToolsExists = fs.existsSync('/Library/Developer/CommandLineTools/usr/bin/');
const xcodeAppExists = fs.existsSync('/Applications/Xcode.app/Contents/Developer/Tools');
const xcodeExists = fs.existsSync('/Library/Developer/Xcode/');
return (cmdLineToolsExists || xcodeExists || xcodeAppExists);
}
function nanoSeconds() {
const time = process.hrtime();
if (!Array.isArray(time) || time.length !== 2) {
return 0;
}
return +time[0] * 1e9 + +time[1];
}
function countUniqueLines(lines, startingWith) {
startingWith = startingWith || '';
const uniqueLines = [];
lines.forEach(line => {
if (line.indexOf(startingWith) === 0) {
if (uniqueLines.indexOf(line) === -1) {
uniqueLines.push(line);
}
}
});
return uniqueLines.length;
}
function noop() { }
exports.toInt = toInt;
exports.execOptsWin = execOptsWin;
exports.getCodepage = getCodepage;
exports.execWin = execWin;
exports.isFunction = isFunction;
exports.unique = unique;
exports.sortByKey = sortByKey;
exports.cores = cores;
exports.getValue = getValue;
exports.decodeEscapeSequence = decodeEscapeSequence;
exports.parseDateTime = parseDateTime;
exports.parseHead = parseHead;
exports.findObjectByKey = findObjectByKey;
exports.getWmic = getWmic;
exports.wmic = wmic;
exports.darwinXcodeExists = darwinXcodeExists;
exports.getVboxmanage = getVboxmanage;
exports.powerShell = powerShell;
exports.nanoSeconds = nanoSeconds;
exports.countUniqueLines = countUniqueLines;
exports.noop = noop;
exports.isRaspberry = isRaspberry;
exports.isRaspbian = isRaspbian;
'use strict';
// @ts-check
// ==================================================================================
// virtualbox.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 14. Docker
// ----------------------------------------------------------------------------------
const os = require('os');
const exec = require('child_process').exec;
const util = require('./util');
function vboxInfo(callback) {
// fallback - if only callback is given
let result = [];
return new Promise((resolve) => {
process.nextTick(() => {
try {
exec(util.getVboxmanage() + ' list vms --long', function (error, stdout) {
let parts = (os.EOL + stdout.toString()).split(os.EOL + 'Name:');
parts.shift();
parts.forEach(part => {
const lines = ('Name:' + part).split(os.EOL);
const state = util.getValue(lines, 'State');
const running = state.startsWith('running');
const runningSinceString = running ? state.replace('running (since ', '').replace(')', '').trim() : '';
let runningSince = 0;
try {
if (running) {
const sinceDateObj = new Date(runningSinceString);
const offset = sinceDateObj.getTimezoneOffset();
runningSince = Math.round((Date.now() - Date.parse(sinceDateObj)) / 1000) + offset * 60;
}
} catch (e) {
util.noop();
}
const stoppedSinceString = !running ? state.replace('powered off (since', '').replace(')', '').trim() : '';
let stoppedSince = 0;
try {
if (!running) {
const sinceDateObj = new Date(stoppedSinceString);
const offset = sinceDateObj.getTimezoneOffset();
stoppedSince = Math.round((Date.now() - Date.parse(sinceDateObj)) / 1000) + offset * 60;
}
} catch (e) {
util.noop();
}
result.push({
id: util.getValue(lines, 'UUID'),
name: util.getValue(lines, 'Name'),
running,
started: runningSinceString,
runningSince,
stopped: stoppedSinceString,
stoppedSince,
guestOS: util.getValue(lines, 'Guest OS'),
hardwareUUID: util.getValue(lines, 'Hardware UUID'),
memory: parseInt(util.getValue(lines, 'Memory size', ' '), 10),
vram: parseInt(util.getValue(lines, 'VRAM size'), 10),
cpus: parseInt(util.getValue(lines, 'Number of CPUs'), 10),
cpuExepCap: util.getValue(lines, 'CPU exec cap'),
cpuProfile: util.getValue(lines, 'CPUProfile'),
chipset: util.getValue(lines, 'Chipset'),
firmware: util.getValue(lines, 'Firmware'),
pageFusion: util.getValue(lines, 'Page Fusion') === 'enabled',
configFile: util.getValue(lines, 'Config file'),
snapshotFolder: util.getValue(lines, 'Snapshot folder'),
logFolder: util.getValue(lines, 'Log folder'),
HPET: util.getValue(lines, 'HPET') === 'enabled',
PAE: util.getValue(lines, 'PAE') === 'enabled',
longMode: util.getValue(lines, 'Long Mode') === 'enabled',
tripleFaultReset: util.getValue(lines, 'Triple Fault Reset') === 'enabled',
APIC: util.getValue(lines, 'APIC') === 'enabled',
X2APIC: util.getValue(lines, 'X2APIC') === 'enabled',
ACPI: util.getValue(lines, 'ACPI') === 'enabled',
IOAPIC: util.getValue(lines, 'IOAPIC') === 'enabled',
biosAPICmode: util.getValue(lines, 'BIOS APIC mode'),
bootMenuMode: util.getValue(lines, 'Boot menu mode'),
bootDevice1: util.getValue(lines, 'Boot Device 1'),
bootDevice2: util.getValue(lines, 'Boot Device 2'),
bootDevice3: util.getValue(lines, 'Boot Device 3'),
bootDevice4: util.getValue(lines, 'Boot Device 4'),
timeOffset: util.getValue(lines, 'Time offset'),
RTC: util.getValue(lines, 'RTC'),
});
});
if (callback) { callback(result); }
resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
resolve(result);
}
});
});
}
exports.vboxInfo = vboxInfo;
'use strict';
// @ts-check
// ==================================================================================
// wifi.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2019
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 9. wifi
// ----------------------------------------------------------------------------------
const os = require('os');
const exec = require('child_process').exec;
const util = require('./util');
let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
function wifiDBFromQuality(quality) {
return (parseFloat(quality) / 2 - 100);
}
function wifiQualityFromDB(db) {
const result = 2 * (parseFloat(db) + 100);
return result <= 100 ? result : 100;
}
function wifiFrequencyFromChannel(channel) {
const frequencies = {
1: 2412,
2: 2417,
3: 2422,
4: 2427,
5: 2432,
6: 2437,
7: 2442,
8: 2447,
9: 2452,
10: 2457,
11: 2462,
12: 2467,
13: 2472,
14: 2484,
32: 5160,
34: 5170,
36: 5180,
38: 5190,
40: 5200,
42: 5210,
44: 5220,
46: 5230,
48: 5240,
50: 5250,
52: 5260,
54: 5270,
56: 5280,
58: 5290,
60: 5300,
62: 5310,
64: 5320,
68: 5340,
96: 5480,
100: 5500,
102: 5510,
104: 5520,
106: 5530,
108: 5540,
110: 5550,
112: 5560,
114: 5570,
116: 5580,
118: 5590,
120: 5600,
122: 5610,
124: 5620,
126: 5630,
128: 5640,
132: 5660,
134: 5670,
136: 5680,
138: 5690,
140: 5700,
142: 5710,
144: 5720,
149: 5745,
151: 5755,
153: 5765,
155: 5775,
157: 5785,
159: 5795,
161: 5805,
165: 5825,
169: 5845,
173: 5865,
183: 4915,
184: 4920,
185: 4925,
187: 4935,
188: 4940,
189: 4945,
192: 4960,
196: 4980
};
return frequencies.hasOwnProperty(channel) ? frequencies[channel] : -1;
}
function wifiNetworks(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = [];
if (_linux) {
let cmd = 'nmcli --terse --fields active,ssid,bssid,mode,chan,freq,signal,security,wpa-flags,rsn-flags device wifi list';
exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
const parts = stdout.toString().split('ACTIVE:');
parts.shift();
parts.forEach(part => {
part = 'ACTIVE:' + part;
const lines = part.split(os.EOL);
const channel = util.getValue(lines, 'CHAN');
const frequency = util.getValue(lines, 'FREQ').toLowerCase().replace('mhz', '').trim();
const security = util.getValue(lines, 'SECURITY').replace('(', '').replace(')', '');
const wpaFlags = util.getValue(lines, 'WPA-FLAGS').replace('(', '').replace(')', '');
const rsnFlags = util.getValue(lines, 'RSN-FLAGS').replace('(', '').replace(')', '');
result.push({
ssid: util.getValue(lines, 'SSID'),
bssid: util.getValue(lines, 'BSSID'),
mode: util.getValue(lines, 'MODE'),
channel: channel ? parseInt(channel, 10) : -1,
frequency: frequency ? parseInt(frequency, 10) : -1,
signalLevel: wifiDBFromQuality(util.getValue(lines, 'SIGNAL')),
quality: parseFloat(util.getValue(lines, 'SIGNAL')),
security: security && security !== 'none' ? security.split(' ') : [],
wpaFlags: wpaFlags && wpaFlags !== 'none' ? wpaFlags.split(' ') : [],
rsnFlags: rsnFlags && rsnFlags !== 'none' ? rsnFlags.split(' ') : []
});
});
if (callback) {
callback(result);
}
resolve(result);
});
} else if (_darwin) {
let cmd = '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s';
exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
const lines = stdout.toString().split(os.EOL);
if (lines && lines.length > 1) {
const parsedhead = util.parseHead(lines[0], 1);
if (parsedhead.length >= 7) {
lines.shift();
lines.forEach(line => {
if (line.trim()) {
const channelStr = line.substring(parsedhead[3].from, parsedhead[3].to).trim();
const channel = channelStr ? parseInt(channelStr, 10) : -1;
const signalLevel = line.substring(parsedhead[2].from, parsedhead[2].to).trim();
const securityAll = line.substring(parsedhead[6].from, 1000).trim().split(' ');
let security = [];
let wpaFlags = [];
securityAll.forEach(securitySingle => {
if (securitySingle.indexOf('(') > 0) {
const parts = securitySingle.split('(');
security.push(parts[0]);
wpaFlags = wpaFlags.concat(parts[1].replace(')', '').split(','));
}
});
wpaFlags = Array.from(new Set(wpaFlags));
result.push({
ssid: line.substring(parsedhead[0].from, parsedhead[0].to).trim(),
bssid: line.substring(parsedhead[1].from, parsedhead[1].to).trim(),
mode: '',
channel,
frequency: wifiFrequencyFromChannel(channel),
signalLevel: signalLevel ? parseInt(signalLevel, 10) : -1,
quality: wifiQualityFromDB(signalLevel),
security,
wpaFlags,
rsnFlags: []
});
}
});
}
}
if (callback) {
callback(result);
}
resolve(result);
});
} else if (_windows) {
let cmd = 'chcp 65001 && netsh wlan show networks mode=Bssid';
exec(cmd, util.execOptsWin, function (error, stdout) {
const parts = stdout.toString('utf8').split(os.EOL + os.EOL + 'SSID ');
parts.shift();
parts.forEach(part => {
const lines = part.split(os.EOL);
if (lines && lines.length >= 8 && lines[0].indexOf(':') >= 0) {
let bssid = lines[4].split(':');
bssid.shift();
bssid = bssid.join(':').trim();
const channel = lines[7].split(':').pop().trim();
const quality = lines[5].split(':').pop().trim();
result.push({
ssid: lines[0].split(':').pop().trim(),
bssid,
mode: '',
channel: channel ? parseInt(channel, 10) : -1,
frequency: wifiFrequencyFromChannel(channel),
signalLevel: wifiDBFromQuality(quality),
quality: quality ? parseInt(quality, 10) : -1,
security: [lines[2].split(':').pop().trim()],
wpaFlags: [lines[3].split(':').pop().trim()],
rsnFlags: []
});
}
});
if (callback) {
callback(result);
}
resolve(result);
});
} else {
if (callback) {
callback(result);
}
resolve(result);
}
});
});
}
exports.wifiNetworks = wifiNetworks;
{
"_from": "systeminformation",
"_id": "systeminformation@4.14.11",
"_inBundle": false,
"_integrity": "sha512-KlMaQQftyGUPjKzGRrATN5mpKrpdtrVk/KPuqPeu733bUgpokIhevg5zjKOb4Gur91XKdbdQCCja/oFsg5R4Dw==",
"_location": "/systeminformation",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "systeminformation",
"name": "systeminformation",
"escapedName": "systeminformation",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.14.11.tgz",
"_shasum": "5c7f23d92586f2639a9d037a359890f7ab01c4ea",
"_spec": "systeminformation",
"_where": "C:\\Users\\thequ\\Documents\\Mynij",
"author": {
"name": "Sebastian Hildebrandt",
"email": "hildebrandt@plus-innovations.com",
"url": "https://plus-innovations.com"
},
"bugs": {
"url": "https://github.com/sebhildebrandt/systeminformation/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Simple system and OS information library",
"devDependencies": {
"@types/chai": "^4.1.7",
"@types/mocha": "^5.2.5",
"@types/node": "^10.12.18",
"chai": "^4.2.0",
"coveralls": "^3.0.2",
"mocha": "^5.2.0",
"nyc": "^13.1.0",
"rimraf": "^2.6.2",
"source-map-support": "^0.5.9",
"ts-node": "^7.0.1",
"typescript": "^3.2.2"
},
"engines": {
"node": ">=4.0.0"
},
"files": [
"lib/"
],
"homepage": "https://github.com/sebhildebrandt/systeminformation",
"keywords": [
"system information",
"sysinfo",
"monitor",
"monitoring",
"os",
"linux",
"osx",
"windows",
"freebsd",
"openbsd",
"netbsd",
"cpu",
"cpuload",
"physical cores",
"logical cores",
"processor",
"cores",
"threads",
"socket type",
"memory",
"file system",
"fsstats",
"diskio",
"block devices",
"netstats",
"network",
"network interfaces",
"network connections",
"network stats",
"iface",
"processes",
"users",
"internet",
"battery",
"docker",
"docker stats",
"docker processes",
"graphics",
"graphic card",
"graphic controller",
"gpu",
"display",
"smart",
"disk layout",
"wifi",
"wifinetworks",
"virtual box",
"virtualbox",
"vm"
],
"license": "MIT",
"main": "./lib/index.js",
"name": "systeminformation",
"nyc": {
"extension": [
".js"
],
"include": [
"lib/**"
],
"exclude": [
"**/*.d.ts"
],
"reporter": [
"html",
"text"
],
"all": true
},
"os": [
"darwin",
"linux",
"win32",
"freebsd",
"openbsd",
"netbsd",
"sunos"
],
"repository": {
"type": "git",
"url": "git+https://github.com/sebhildebrandt/systeminformation.git"
},
"scripts": {
"clean": "rimraf dist",
"compile": "tsc",
"coverage": "nyc report --reporter=text-lcov",
"test": "nyc mocha --require ts-node/register --require source-map-support/register ./test/**/*.test.ts",
"test-bare": "npm run compile && mocha ./test/**/*.test.js",
"watch": "tsc -w"
},
"types": "./lib/index.d.ts",
"version": "4.14.11"
}
...@@ -417,6 +417,11 @@ ...@@ -417,6 +417,11 @@
"ansi-regex": "^4.1.0" "ansi-regex": "^4.1.0"
} }
}, },
"systeminformation": {
"version": "4.14.11",
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.14.11.tgz",
"integrity": "sha512-KlMaQQftyGUPjKzGRrATN5mpKrpdtrVk/KPuqPeu733bUgpokIhevg5zjKOb4Gur91XKdbdQCCja/oFsg5R4Dw=="
},
"typedarray": { "typedarray": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment