diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3087260 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +# For more information about the properties used in +# this file, please see the EditorConfig documentation: +# http://editorconfig.org/ + +# top-most EditorConfig file +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = true + +[{.travis.yml,package.json}] +# The indent size used in the `package.json` file cannot be changed +# https://github.com/npm/npm/pull/3180#issuecomment-16336516 +indent_style = space +indent_size = 2 diff --git a/README.md b/README.md index 79f780b..db759a4 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ Simple system and OS information library for [node.js][nodejs-url] [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] + [![Git Issues][issues-img]][issues-url] + [![deps status][daviddm-img]][daviddm-url] [![MIT license][license-img]][license-url] ## Quick Start @@ -21,19 +23,52 @@ All functions (except `version` and `time`) are implemented as asynchronous func ``` var si = require('systeminformation'); +// callback style si.cpu(function(data) { console.log('CPU-Information:'); console.log(data); }) + +// promises style +si.cpu() + .then(data => console.log(data)) + .catch(error => console.error(error)); + ``` -### Major Changes - Version 2 +### Major (breaking) Changes - Version 3 -There are a lot of changes in version 2 of systeminformation! Here is a quick overview: +- 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 above, you can now also use it in a promise oriented way. But callbacks are still supported. +- `cpuCurrentspeed`: now returns an object with current minimal, maximal and average CPU frequencies of all cores. +- `networkInterfaces`: now providing one more detail: internal - true if this is an internal interface like "lo" +- `mem`: now supports also `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) +- `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 +New Functions -- `version`: returns systeminformation version (semver) +- `disksIO`: returns overall diskIO and IOPS values for all mounted volumes + +Bug Fixes + +- several bug fixes (like assess errors) +- 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) @@ -61,12 +96,12 @@ 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) +- `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) +- `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 +- `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 @@ -75,15 +110,14 @@ Other changes - 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 ;-) -**Be aware**, that the new version 2.x is **NOT backward compatible** to version 1.x .... - ## 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. In version 2 I cleaned up a lot of inconsistencies and bugs, but -there is for sure room for improvement. I was only able to test it on several Debian, Raspbian, Ubuntu distributions as well -as OS X (Mavericks, Yosemite, El Captain). Version 2 now also supports nearly all functionality on OS X/Darwin platforms. -But be careful, this library will definitely NOT work on Windows platforms! +[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. Version 3 comes with further improvements. First it +requires now node.js version 4.0 and above. Another big change is, that all functions now return promises. You can use them +like before with callbacks OR with promises (see example in this documentation). I am sure, there is for sure room for improvement. +I was only able to test it on several Debian, Raspbian, Ubuntu distributions as well as OS X (Mavericks, Yosemite, El Captain). +Since version 2 nearly all functionality is available on OS X/Darwin platforms. But be careful, this library will definitely NOT work on Windows platforms! If you have comments, suggestions & reports, please feel free to contact me! @@ -133,17 +167,21 @@ This library is splitted in several sections: | - brand | X | X | e.g. 'Core(TM)2 Duo' | | - speed | X | X | in GHz e.g. '3.40' | | - cores | X | X | # cores | -| si.cpuCurrentspeed(cb) | X | X | current speed (in GHz)| +| si.cpuCurrentspeed(cb) | X | X | current CPU speed (in GHz)| +| - avg | X | | avg CPU speed (all cores) | +| - min | X | | min CPU speed (all cores) | +| - max | X | | max CPU speed (all cores) | | si.cpuTemperature(cb) | X | | CPU temperature (if sensors is installed) | | - main | X | | main temperature | | - cores | X | | array of temperatures | | - max | X | | max temperature | | si.mem(cb) | X | X | Memory information| -| - total | X | X | | -| - free | X | X | | -| - used | X | X | | -| - active | X | X | | -| - buffcache | X | X | | +| - total | X | X | total memory | +| - free | X | X | not used | +| - used | X | X | used (incl. buffers/cache) | +| - active | X | X | used actively (excl. buffers/cache) | +| - buffcache | X | X | used by buffers+cache | +| - available | X | X | potentially available (total - active) | | - swaptotal | X | X | | | - swapused | X | X | | | - swapfree | X | X | | @@ -156,19 +194,39 @@ This library is splitted in several sections: | 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) | +| 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 | | interval length (for per second values) | | si.networkInterfaces(cb) | X | X | array of network interfaces | | - [0].iface | X | X | interface name | | - [0].ip4 | X | X | ip4 address | | - [0].ip6 | X | X | ip6 address | -| si.networkStats('eth1',cb) | X | X | current network stats of given interface | +| - [0].internal | X | X | true if internal interface | +| si.networkStats(iface,cb) | X | X | current network stats of given interface
iface parameter is optional
defaults to first external network interface| | - iface | X | X | interface | | - operstate | X | X | up / down | | - rx | X | X | received bytes overall | | - tx | X | X | transferred bytes overall| | - rx_sec | X | X | received bytes / second (* see notes) | | - tx_sec | X | X | transferred bytes per second (* see notes) | +| - ms | X | X | interval length (for per second values) | +| si.networkConnections(cb) | X | X | current network network connections
returns an array of all connections| +| - [0].protocol | X | X | tcp or udp | +| - [0].localaddress | X | X | local address | +| - [0].localport | X | X | local port | +| - [0].peeraddress | X | X | peer address | +| - [0].peerport | X | X | peer port | +| - [0].state | X | X | like ESTABLISHED, TIME_WAIT, ... | | si.currentLoad(cb) | X | X | CPU-Load in % | | si.fullLoad(cb) | X | X | CPU-full load since bootup in % | | si.services('mysql, apache2', cb) | X | X | pass comma separated string of services | @@ -183,20 +241,27 @@ This library is splitted in several sections: | - cpu | X | X | process % CPU | | - mem | X | X | process % MEM | | si.users(cb) | X | X | array of users online | +| - [0].user | X | X | user name | +| - [0].tty | X | X | terminal | +| - [0].date | X | X | login date | +| - [0].time | X | X | login time | +| - [0].ip | X | X | ip address (remote login) | +| - [0].command | X | X | last command or shell | | si.inetChecksite(url, cb) | X | X | response-time (ms) to fetch given URL | | - url | X | X | given url | | - ok | X | X | status code OK (2xx, 3xx) | | - status | X | X | status code | | - ms | X | X | response time in ms | -| si.inetLatency(cb) | X | X | response-time (ms) to external ressource | +| si.inetLatency(host, cb) | X | X | response-time (ms) to external resource
host parameter is optional (default 8.8.8.8)| | si.getStaticData(cb) | X | X | all static data at once | -| si.getDynamicData(cb,srv,iface) | X | X | all dynamic data at once | -| si.getAllData(cb,srv,iface) | X | X | all data at once | +| si.getDynamicData(srv,iface,cb) | X | X | all dynamic data at once | +| si.getAllData(srv,iface,cb) | X | X | all data at once | ### cb: Asynchronous Function Calls (callback) -Remember: all functions (except `version` and `time`) are implemented as asynchronous (callback) functions! -So another example, how to use a specific function might be: +Remember: all functions (except `version` and `time`) are implemented as asynchronous functions! There are now two ways to consume them: + +**Callback Style** ``` var si = require('systeminformation'); @@ -211,17 +276,35 @@ si.networkStats('eth1', function(data) { }) ``` +**Promises Style** (new in version 3.0) + +When omitting callback parameter (cb), then you can use all function in a promise oriented way: + +``` +si.networkStats('eth1') + .then(data => { + console.log('Network Interface Stats (eth1):'); + console.log('- is up: ' + data.operstate); + console.log('- RX bytes overall: ' + data.rx); + console.log('- TX bytes overall: ' + data.tx); + console.log('- RX bytes/sec: ' + data.rx_sec); + console.log('- TX bytes/sec: ' + data.tx_sec); + }) + .catch(error => console.error(error)); + +``` + ### *: Additional Notes -In `fsStats` and `networkStats` the results per second values (rx_sec, ...) are calculated beginning -with the second call of the function. It is determined by calculating the difference of transferred bytes +In `fsStats`, `disksIO` and `networkStats` the results per second values (rx_sec, IOPS, ...) are calculated 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. ## Known Issues There is one major things, that I was still not able to solve: -For OS X, I did not find a reliable way to get the CPU temperature. All suggestions I found did not work on current version of OS X on different machines (intel platform). So if anyone has an idea, this would be helpful. +For OS X, I did not find a reliable way to get the CPU temperature. All suggestions I found did not work on current version of OS X on different machines (intel platform). So if anyone has an idea, this would be helpful. I am happy to discuss any comments and suggestions. Please feel free to contact me if you see any possibility of improvement! @@ -229,6 +312,7 @@ I am happy to discuss any comments and suggestions. Please feel free to contact | Version | Date | Comment | | -------------- | -------------- | -------- | +| 3.0.0 | 2016-08-02 | 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 | @@ -266,13 +350,14 @@ Written by Sebastian Hildebrandt [sebhildebrandt](https://github.com/sebhildebra - Guillaume Legrain [glegrain](https://github.com/glegrain) - Riccardo Novaglia [richy24](https://github.com/richy24) +- Quentin Busuttil [Buzut](https://github.com/Buzut) ## Copyright Information -Linux is a registered trademark of Linus Torvalds, OS X is a registered trademark 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, 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. +Linux is a registered trademark of Linus Torvalds, OS X is a registered trademark 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, 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. All other trademarks are the property of their respective owners. ## License [![MIT license][license-img]][license-url] @@ -298,7 +383,7 @@ All other trademarks are the property of their respective owners. >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. @@ -312,3 +397,9 @@ All other trademarks are the property of their respective owners. [npmjs-license]: https://img.shields.io/npm/l/systeminformation.svg?style=flat-square [nodejs-url]: https://nodejs.org/en/ + +[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 diff --git a/lib/index.js b/lib/index.js index 167f81c..a885f5c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,3 +1,4 @@ +'use strict'; // ================================================================================== // index.js // ---------------------------------------------------------------------------------- @@ -8,6 +9,7 @@ // ---------------------------------------------------------------------------------- // Contributors: Guillaume Legrain (https://github.com/glegrain) // Riccardo Novaglia (https://github.com/richy24) +// Quentin Busuttil (https://github.com/Buzut) // ---------------------------------------------------------------------------------- // License: MIT // ================================================================================== @@ -33,7 +35,7 @@ // // # npm install systeminformation --save // -// The new version 2.0 has no more dependencies. +// Since version 2.0 systeminformation has no more dependencies. // // ================================================================================== // @@ -43,20 +45,28 @@ // // var si = require('systeminformation'); // +// // callback style // si.cpu(function(data) { // console.log('CPU-Information:'); // console.log(data); // }) // +// // promises style +// si.cpu() +// .then(data => console.log(data)) +// .catch(error => console.error(error)); +// // ================================================================================== // // Comments // -------------------------------- // -// This library is still work in progress. In version 2 I cleaned up a lot of inconsistencies -// and bugs, but there is for sure room for improvement. I was only able to test it on several +// This library is still work in progress. Version 3 comes with further improvements. First it +// requires now node.js version 4.0 and above. Another big change is, that all functions now +// return promises. You can use them like before with callbacks OR with promises (see documentation +// below. I am sure, there is for sure room for improvement. I was only able to test it on several // Debian, Raspbian, Ubuntu distributions as well as OS X (Mavericks, Yosemite, El Captain). -// Version 2 now also supports nearly all functionality on OS X/Darwin platforms. +// Since version 2 nearly all functionality is available on OS X/Darwin platforms. // But be careful, this library will definitely NOT work on Windows platforms! // // Comments, suggestions & reports are very welcome! @@ -67,6 +77,8 @@ // -------------------------------- // // version date comment +// 3.0.0 2016-08-01 new major version 3.0 +// 2.0.5 2016-02-22 some more tiny correction ... // 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 @@ -90,7 +102,7 @@ // Dependencies // ---------------------------------------------------------------------------------- -var os = require('os') +const os = require('os') , exec = require('child_process').exec , fs = require('fs') , lib_version = require('../package.json').version; @@ -103,6 +115,8 @@ var _windows = (_platform == 'Windows_NT'); var _network = {}; var _cpu_speed = '0.00'; var _fs_speed = {}; +var _disk_io = {}; +var _default_iface; const NOT_SUPPORTED = 'not supported'; @@ -111,8 +125,8 @@ const NOT_SUPPORTED = 'not supported'; // ---------------------------------------------------------------------------------- function isFunction(functionToCheck) { - var getType = {}; - return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; + var getType = {}; + return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; } // ---------------------------------------------------------------------------------- @@ -120,105 +134,113 @@ function isFunction(functionToCheck) { // ---------------------------------------------------------------------------------- function system(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } - var result = { - manufacturer : '-', - model : '-', - version : '-', - serial : '-', - uuid : '-' - }; + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } - if (_linux) { - exec("dmidecode -t system", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); - lines.forEach(function(line) { - if (line.indexOf(':') != -1) { - if (line.toLowerCase().indexOf('manufacturer') != -1) result.manufacturer = line.split(':')[1].trim(); - if (line.toLowerCase().indexOf('product name') != -1) result.model = line.split(':')[1].trim(); - if (line.toLowerCase().indexOf('version') != -1) result.version = line.split(':')[1].trim(); - if (line.toLowerCase().indexOf('serial number') != -1) result.serial = line.split(':')[1].trim(); - if (line.toLowerCase().indexOf('uuid') != -1) result.uuid = line.split(':')[1].trim(); - } - }); - if (result.serial.toLowerCase().indexOf('o.e.m.') != -1) result.serial = '-'; + var result = { + manufacturer: '-', + model: '-', + version: '-', + serial: '-', + uuid: '-' + }; - if (result.manufacturer == '-' && result.model == '-' && result.version == '-') { - // Check Raspberry Pi - exec("grep Hardware /proc/cpuinfo; grep Serial /proc/cpuinfo; grep Revision /proc/cpuinfo", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); - lines.forEach(function(line) { - if (line.indexOf(':') != -1) { - if (line.toLowerCase().indexOf('hardware') != -1) result.model = line.split(':')[1].trim(); - if (line.toLowerCase().indexOf('revision') != -1) result.version = line.split(':')[1].trim(); - if (line.toLowerCase().indexOf('serial') != -1) result.serial = line.split(':')[1].trim(); - } - }); - if (result.model == 'BCM2709') { - result.manufacturer = 'Raspberry Pi Foundation'; - result.model = result.model + ' - Pi 2 Model B'; - if (['a01041', 'a21041'].indexOf(result.version) >= 0) { - result.version = result.version + ' - Rev. 1.1' - } - } - if (result.model == 'BCM2708') { - result.manufacturer = 'Raspberry Pi Foundation'; - if (['0002', '0003'].indexOf(result.version) >= 0) { - result.model = result.model + ' - Pi Model B'; - result.version = result.version + ' - Rev 1.0'; - } - if (['0007', '0008', '0009'].indexOf(result.version) >= 0) { - result.model = result.model + ' - Pi Model A'; - result.version = result.version + ' - Rev 2.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 (['0012'].indexOf(result.version) >= 0) { - result.model = result.model + ' - Pi Model A+'; - result.version = result.version + ' - Rev 1.0'; - } - if (['0010'].indexOf(result.version) >= 0) { - result.model = result.model + ' - Pi Model B+'; - 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'; - } - } - } - }) - } - } - callback(result); - }) - } - if (_darwin) { - exec("ioreg -c IOPlatformExpertDevice -d 2", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); - lines.forEach(function(line) { - line = line.replace(/[<>"]/g, ""); - if (line.indexOf('=') != -1) { - if (line.toLowerCase().indexOf('manufacturer') != -1) result.manufacturer = line.split('=')[1].trim(); - if (line.toLowerCase().indexOf('model') != -1) result.model = line.split('=')[1].trim(); - if (line.toLowerCase().indexOf('version') != -1) result.version = line.split('=')[1].trim(); - if (line.toLowerCase().indexOf('ioplatformserialnumber') != -1) result.serial = line.split('=')[1].trim(); - if (line.toLowerCase().indexOf('ioplatformuuid') != -1) result.uuid = line.split('=')[1].trim(); - } - }); - } - callback(result); - }) - } + if (_linux) { + exec("dmidecode -t system", function (error, stdout) { + if (!error) { + var lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + if (line.indexOf(':') != -1) { + if (line.toLowerCase().indexOf('manufacturer') != -1) result.manufacturer = line.split(':')[1].trim(); + if (line.toLowerCase().indexOf('product name') != -1) result.model = line.split(':')[1].trim(); + if (line.toLowerCase().indexOf('version') != -1) result.version = line.split(':')[1].trim(); + if (line.toLowerCase().indexOf('serial number') != -1) result.serial = line.split(':')[1].trim(); + if (line.toLowerCase().indexOf('uuid') != -1) result.uuid = line.split(':')[1].trim(); + } + }); + if (result.serial.toLowerCase().indexOf('o.e.m.') != -1) result.serial = '-'; + if (result.manufacturer == '-' && result.model == '-' && result.version == '-') { + // Check Raspberry Pi + exec("grep Hardware /proc/cpuinfo; grep Serial /proc/cpuinfo; grep Revision /proc/cpuinfo", function (error, stdout) { + if (!error) { + var lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + if (line.indexOf(':') != -1) { + if (line.toLowerCase().indexOf('hardware') != -1) result.model = line.split(':')[1].trim(); + if (line.toLowerCase().indexOf('revision') != -1) result.version = line.split(':')[1].trim(); + if (line.toLowerCase().indexOf('serial') != -1) result.serial = line.split(':')[1].trim(); + } + }); + if (result.model == 'BCM2709') { + result.manufacturer = 'Raspberry Pi Foundation'; + result.model = result.model + ' - Pi 2 Model B'; + if (['a01041', 'a21041'].indexOf(result.version) >= 0) { + result.version = result.version + ' - Rev. 1.1' + } + } + if (result.model == 'BCM2708') { + result.manufacturer = 'Raspberry Pi Foundation'; + if (['0002', '0003'].indexOf(result.version) >= 0) { + result.model = result.model + ' - Pi Model B'; + result.version = result.version + ' - Rev 1.0'; + } + if (['0007', '0008', '0009'].indexOf(result.version) >= 0) { + result.model = result.model + ' - Pi Model A'; + result.version = result.version + ' - Rev 2.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 (['0012'].indexOf(result.version) >= 0) { + result.model = result.model + ' - Pi Model A+'; + result.version = result.version + ' - Rev 1.0'; + } + if (['0010'].indexOf(result.version) >= 0) { + result.model = result.model + ' - Pi Model B+'; + 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 (callback) { callback(result) } + resolve(result); + }) + } + if (_darwin) { + exec("ioreg -c IOPlatformExpertDevice -d 2", function (error, stdout) { + if (!error) { + var lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + line = line.replace(/[<>"]/g, ""); + if (line.indexOf('=') != -1) { + if (line.toLowerCase().indexOf('manufacturer') != -1) result.manufacturer = line.split('=')[1].trim(); + if (line.toLowerCase().indexOf('model') != -1) result.model = line.split('=')[1].trim(); + if (line.toLowerCase().indexOf('version') != -1) result.version = line.split('=')[1].trim(); + if (line.toLowerCase().indexOf('ioplatformserialnumber') != -1) result.serial = line.split('=')[1].trim(); + if (line.toLowerCase().indexOf('ioplatformuuid') != -1) result.uuid = line.split('=')[1].trim(); + } + }); + } + if (callback) { callback(result) } + resolve(result); + }) + } + }); + }); } exports.system = system; @@ -228,7 +250,7 @@ exports.system = system; // ---------------------------------------------------------------------------------- function version() { - return lib_version; + return lib_version; } exports.version = version; @@ -241,10 +263,10 @@ exports.version = version; // Get current time and OS uptime function time() { - return { - current : Date.now(), - uptime : os.uptime() - }; + return { + current: Date.now(), + uptime: os.uptime() + }; } exports.time = time; @@ -253,35 +275,36 @@ exports.time = time; // Get logo filename of OS distribution function getLogoFile(distro) { - var result = 'linux'; - if (distro.toLowerCase().indexOf('mac os') != -1) { result = 'apple' } else - if (distro.toLowerCase().indexOf('arch') != -1) { result = 'arch' } else - if (distro.toLowerCase().indexOf('centos') != -1) { result = 'centos' } else - if (distro.toLowerCase().indexOf('coreos') != -1) { result = 'coreos' } else - if (distro.toLowerCase().indexOf('debian') != -1) { result = 'debian' } else - if (distro.toLowerCase().indexOf('elementary') != -1) { result = 'elementary' } else - if (distro.toLowerCase().indexOf('fedora') != -1) { result = 'fedora' } else - if (distro.toLowerCase().indexOf('gentoo') != -1) { result = 'gentoo' } else - if (distro.toLowerCase().indexOf('mageia') != -1) { result = 'mageia' } else - if (distro.toLowerCase().indexOf('mandriva') != -1) { result = 'mandriva' } else - if (distro.toLowerCase().indexOf('manjaro') != -1) { result = 'manjaro' } else - if (distro.toLowerCase().indexOf('mint') != -1) { result = 'mint' } else - if (distro.toLowerCase().indexOf('openbsd') != -1) { result = 'openbsd' } else - if (distro.toLowerCase().indexOf('opensuse') != -1) { result = 'opensuse' } else - if (distro.toLowerCase().indexOf('pclinuxos') != -1) { result = 'pclinuxos' } else - if (distro.toLowerCase().indexOf('puppy') != -1) { result = 'puppy' } else - if (distro.toLowerCase().indexOf('raspbian') != -1) { result = 'raspbian' } else - if (distro.toLowerCase().indexOf('reactos') != -1) { result = 'reactos' } else - if (distro.toLowerCase().indexOf('redhat') != -1) { result = 'redhat' } else - if (distro.toLowerCase().indexOf('slackware') != -1) { result = 'slackware' } else - if (distro.toLowerCase().indexOf('sugar') != -1) { result = 'sugar' } else - if (distro.toLowerCase().indexOf('steam') != -1) { result = 'steam' } else - if (distro.toLowerCase().indexOf('suse') != -1) { result = 'suse' } else - if (distro.toLowerCase().indexOf('mate') != -1) { result = 'ubuntu-mate' } else - if (distro.toLowerCase().indexOf('lubuntu') != -1) { result = 'lubuntu' } else - if (distro.toLowerCase().indexOf('xubuntu') != -1) { result = 'xubuntu' } else - if (distro.toLowerCase().indexOf('ubuntu') != -1) { result = 'ubuntu' } - return result; + distro = distro.toLowerCase(); + let result = 'linux'; + 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('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('openbsd') != -1) { result = 'openbsd' } + 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' } + return result; } // -------------------------- @@ -289,54 +312,62 @@ function getLogoFile(distro) { function osInfo(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } - var result = { + var result = { - platform : _platform, - distro : 'unknown', - release : 'unknown', - codename : '', - kernel : os.release(), - arch : os.arch(), - hostname : os.hostname(), - logofile : '' - }; + platform: _platform, + distro: 'unknown', + release: 'unknown', + codename: '', + kernel: os.release(), + arch: os.arch(), + hostname: os.hostname(), + logofile: '' + }; - if (_linux) { + if (_linux) { - exec("cat /etc/*-release", function(error, stdout) { - if (!error) { - var release = {}; - var lines = stdout.toString().split('\n'); - lines.forEach(function(line) { - if (line.indexOf('=') != -1) { - release[line.split('=')[0].trim().toUpperCase()] = line.split('=')[1].trim(); - } - }); - result.distro = (release.DISTRIB_ID || release.NAME || 'unknown').replace(/"/g, ''); - result.logofile = getLogoFile(result.distro); - result.release = (release.DISTRIB_RELEASE || release.VERSION_ID || 'unknown').replace(/"/g, ''); - result.codename = (release.DISTRIB_CODENAME || '').replace(/"/g, ''); - } - callback(result); - }) - } - if (_darwin) { - exec("sw_vers", function(error, stdout) { - var lines = stdout.toString().split('\n'); - lines.forEach(function(line) { - if (line.indexOf('ProductName') != -1) { - result.distro = line.split(':')[1].trim(); - result.logofile = getLogoFile(result.distro); - } - if (line.indexOf('ProductVersion') != -1) result.release = line.split(':')[1].trim(); - }); - callback(result); - }) - } + exec("cat /etc/*-release", function (error, stdout) { + if (!error) { + var release = {}; + var lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + if (line.indexOf('=') != -1) { + release[line.split('=')[0].trim().toUpperCase()] = line.split('=')[1].trim(); + } + }); + result.distro = (release.DISTRIB_ID || release.NAME || 'unknown').replace(/"/g, ''); + result.logofile = getLogoFile(result.distro); + result.release = (release.DISTRIB_RELEASE || release.VERSION_ID || 'unknown').replace(/"/g, ''); + result.codename = (release.DISTRIB_CODENAME || '').replace(/"/g, ''); + } + if (callback) { callback(result) } + resolve(result); + }) + } + if (_darwin) { + exec("sw_vers", function (error, stdout) { + var lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + if (line.indexOf('ProductName') != -1) { + result.distro = line.split(':')[1].trim(); + result.logofile = getLogoFile(result.distro); + } + if (line.indexOf('ProductVersion') != -1) result.release = line.split(':')[1].trim(); + }); + if (callback) { callback(result) } + resolve(result); + }) + } + }); + }); } exports.osInfo = osInfo; @@ -346,89 +377,119 @@ exports.osInfo = osInfo; // ---------------------------------------------------------------------------------- function cpuBrandManufacturer(res) { - res.brand = res.brand.replace(/\(R\)+/g, "®"); - res.brand = res.brand.replace(/\(TM\)+/g, "™"); - res.brand = res.brand.replace(/\(C\)+/g, "©"); - res.brand = res.brand.replace(/CPU+/g, "").trim(); - res.manufacturer = res.brand.split(' ')[0]; - var parts = res.brand.split(' '); - parts.shift(); - res.brand = parts.join(' '); - return res; + res.brand = res.brand.replace(/\(R\)+/g, "®"); + res.brand = res.brand.replace(/\(TM\)+/g, "™"); + res.brand = res.brand.replace(/\(C\)+/g, "©"); + res.brand = res.brand.replace(/CPU+/g, "").trim(); + res.manufacturer = res.brand.split(' ')[0]; + + let parts = res.brand.split(' '); + parts.shift(); + res.brand = parts.join(' '); + return res; } // -------------------------- // CPU - brand, speed -function getCpu(callback) { +function getCpu() { - var result = { - manufacturer : 'unknown', - brand : 'unknown', - speed : '0.00', - cores : _cores - }; - if (_darwin) { - exec("sysctl -n machdep.cpu.brand_string", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); - result.brand = lines[0].split('@')[0].trim(); - result.speed = lines[0].split('@')[1].trim(); - result.speed = parseFloat(result.speed.replace(/GHz+/g, "")); - _cpu_speed = result.speed; - } - result = cpuBrandManufacturer(result); - callback(result); - }); - } - if (_linux) { - exec("cat /proc/cpuinfo | grep 'model name'", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); - var line = lines[0].split(':')[1]; - result.brand = line.split('@')[0].trim(); - result.speed = line.split('@')[1] ? parseFloat(line.split('@')[1].trim()).toFixed(2) : '0.00'; - if (result.speed == '0.00') { - var current = getCpuCurrentSpeedSync(); - if (current != '0.00') result.speed = current; - } - _cpu_speed = result.speed; - } - result = cpuBrandManufacturer(result); - callback(result); - }) - } + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + + var result = { + manufacturer: 'unknown', + brand: 'unknown', + speed: '0.00', + cores: _cores + }; + if (_darwin) { + exec("sysctl -n machdep.cpu.brand_string", function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + result.brand = lines[0].split('@')[0].trim(); + result.speed = lines[0].split('@')[1].trim(); + result.speed = parseFloat(result.speed.replace(/GHz+/g, "")); + _cpu_speed = result.speed; + } + result = cpuBrandManufacturer(result); + resolve(result); + }); + } + if (_linux) { + exec("cat /proc/cpuinfo | grep 'model name'", function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + let line = lines[0].split(':')[1]; + result.brand = line.split('@')[0].trim(); + result.speed = line.split('@')[1] ? parseFloat(line.split('@')[1].trim()).toFixed(2) : '0.00'; + if (result.speed == '0.00') { + let current = getCpuCurrentSpeedSync(); + if (current != '0.00') result.speed = current; + } + _cpu_speed = result.speed; + } + result = cpuBrandManufacturer(result); + resolve(result); + }) + } + }); + }); } // -------------------------- // CPU - Processor cores -function cores(callback) { - exec("grep -c ^processor /proc/cpuinfo 2>/dev/null || sysctl -n hw.ncpu", function(error, stdout) { - var result = {cores: 1}; - if (!error) { - result.cores = parseInt(stdout.toString()); - _cores = result.cores; - } - if (callback) callback(result); - }) +function cores() { + + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + let result = os.cpus().length; + resolve(result); + }); + }); } // -------------------------- // CPU - Processor Data function cpu(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } - if (_cores == 0) { - cores(function() { - getCpu(callback) - }) - } else { - getCpu(callback) - } + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + + if (_cores == 0) { + cores() + .then(data => { + _cores = data; + getCpu().then(result => { + if (callback) { callback(result) } + resolve(result); + }) + }) + } else { + getCpu().then(result => { + if (callback) { callback(result) } + resolve(result); + }) + } + }); + }); } exports.cpu = cpu; @@ -437,40 +498,52 @@ exports.cpu = cpu; // CPU - current speed - in GHz function getCpuCurrentSpeedSync() { - var output = ""; - var result = "0.00"; - if (fs.existsSync("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq")) { - output = fs.readFileSync("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq").toString(); - } else if (fs.existsSync("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq")) { - output = fs.readFileSync("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq").toString(); - } - if (output.trim()) { - var lines = output.toString().split('\n'); - result = parseFloat((parseInt(lines[0]) / 1000 / 1000).toFixed(2)); - } - return result; + + let cpus = os.cpus(); + let minFreq = 999999999; + let maxFreq = 0; + let avgFreq = 0; + + 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; + } + } + avgFreq = avgFreq / cpus.length; + return { + min: parseFloat((minFreq / 1000).toFixed(2)), + max: parseFloat((maxFreq / 1000).toFixed(2)), + avg: parseFloat((avgFreq / 1000).toFixed(2)) + } + } else { + return { + min: 0, + max: 0, + avg: 0 + } + } } function cpuCurrentspeed(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } - var result = _cpu_speed; - if (_darwin) { - exec("sysctl -n hw.cpufrequency", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); - result = parseFloat((parseInt(lines[0]) / 1000 / 1000 / 1000).toFixed(2)); - } - callback(result); - }); - } - if (_linux) { - result = getCpuCurrentSpeedSync(); - if (result == '0.00' && _cpu_speed != '0.00') result = _cpu_speed; - callback(result); - } + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + + let result = getCpuCurrentSpeedSync(); + if (result == 0 && _cpu_speed != '0.00') result = parseFloat(_cpu_speed); + + if (callback) { callback(result) } + resolve(result); + }); + }); } exports.cpuCurrentspeed = cpuCurrentspeed; @@ -480,52 +553,62 @@ exports.cpuCurrentspeed = cpuCurrentspeed; // if sensors are installed function cpuTemperature(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } - var result = { - main : -1.0, - cores : [], - max : -1.0 - }; - if (_linux) { - var regex = /\+([^°]*)/g; - exec("sensors", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); - lines.forEach(function(line) { - var temps = line.match(regex); - if (line.split(':')[0].toUpperCase().indexOf('PHYSICAL') != -1) { - result.main = parseFloat(temps); - } - if (line.split(':')[0].toUpperCase().indexOf('CORE ') != -1) { - result.cores.push(parseFloat(temps)); - } - }); - if (result.cores.length > 0) { - var maxtmp = Math.max.apply(Math, result.cores); - result.max = (maxtmp > result.main) ? maxtmp : result.main; - } - callback(result) - } else { - exec("/opt/vc/bin/vcgencmd measure_temp", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); - if (lines.length > 0 && lines[0].indexOf('=')) { - result.main = parseFloat(lines[0].split("=")[1]); - result.max = result.main - } - } - callback(result) - }); + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } - } - }); - } - if (_darwin) { - callback(result) - } + var 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); + if (line.split(':')[0].toUpperCase().indexOf('PHYSICAL') != -1) { + result.main = parseFloat(temps); + } + if (line.split(':')[0].toUpperCase().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 { + 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 (_darwin) { + if (callback) { callback(result) } + resolve(result); + } + }); + }); } exports.cpuTemperature = cpuTemperature; @@ -534,79 +617,138 @@ exports.cpuTemperature = cpuTemperature; // 5. Memory // ---------------------------------------------------------------------------------- -// | R A M | H D | -// |_________________|__________________________| | | -// | active buffers/cache | | | -// |____________________________________________|___________|_________|______________| -// | used free | used free | -// |________________________________________________________|________________________| -// | total | swap | -// | | | +// | 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 function mem(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } - var result = { - total : os.totalmem(), - free : os.freemem(), - used : os.totalmem() - os.freemem(), + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } - active : os.totalmem() - os.freemem(), - buffcache : 0, + var result = { + total: os.totalmem(), + free: os.freemem(), + used: os.totalmem() - os.freemem(), - swaptotal : 0, - swapused : 0, - swapfree : 0 - }; + active: os.totalmem() - os.freemem(), // temporarily (fallback) + available: os.freemem(), // temporarily (fallback) + buffcache: 0, - if (_linux) { - exec("free -b", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); + swaptotal: 0, + swapused: 0, + swapfree: 0 + }; - var mem = lines[1].replace(/ +/g, " ").split(' '); - result.total = parseInt(mem[1]); - result.free = parseInt(mem[3]); - result.buffcache = parseInt(mem[5]) + parseInt(mem[6]); - result.active = result.total - result.free - result.buffcache; + if (_linux) { + exec("free -b", function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); - mem = lines[3].replace(/ +/g, " ").split(' '); - result.swaptotal = parseInt(mem[1]); - result.swapfree = parseInt(mem[3]); - result.swapused = parseInt(mem[2]); + let mem = lines[1].replace(/ +/g, " ").split(' '); + result.total = parseInt(mem[1]); + result.free = parseInt(mem[3]); - } - callback(result); - }); - } - if (_darwin) { - exec("vm_stat | grep 'Pages active'", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); + if (lines.length === 4) { // free (since free von procps-ng 3.3.10) + result.buffcache = parseInt(mem[5]); + result.available = parseInt(mem[6]); + mem = lines[2].replace(/ +/g, " ").split(' '); + } else { // free (older versions) + result.buffcache = parseInt(mem[5]) + parseInt(mem[6]); + result.available = result.free + result.buffcache; + mem = lines[3].replace(/ +/g, " ").split(' '); + } + result.active = result.total - result.free - result.buffcache; - result.active = parseInt(lines[0].split(':')[1]) * 4096; - result.buffcache = result.used - result.active; - } - exec("sysctl -n vm.swapusage", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); - if (lines.length > 0) { - var line = lines[0].replace(/,/g, ".").replace(/M/g, ""); - line = line.trim().split(' '); - for (var 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; + result.swaptotal = parseInt(mem[1]); + result.swapfree = parseInt(mem[3]); + result.swapused = parseInt(mem[2]); - } - } - } - callback(result); - }); - }); - } + } + 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]) * 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); + }); + }); + } + }); + }); } exports.mem = mem; @@ -619,30 +761,38 @@ exports.mem = mem; // FS - devices function fsSize(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } - exec("df -lk | grep ^/", function(error, stdout) { - var data = []; - if (!error) { - var lines = stdout.toString().split('\n'); - //lines.splice(0, 1); - lines.forEach(function (line) { - if (line != '') { - line = line.replace(/ +/g, " ").split(' '); - data.push({ - 'fs': line[0], - 'size': parseInt(line[1]) * 1024, - 'used': parseInt(line[2]) * 1024, - 'use': parseFloat((100.0 * line[2] / line[1]).toFixed(2)), - 'mount': line[line.length - 1] - }) - } - }); - } - callback(data) - }); + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + + exec("df -lk | grep ^/", function (error, stdout) { + let data = []; + if (!error) { + let lines = stdout.toString().split('\n'); + //lines.splice(0, 1); + lines.forEach(function (line) { + if (line != '') { + line = line.replace(/ +/g, " ").split(' '); + data.push({ + 'fs': line[0], + 'size': parseInt(line[1]) * 1024, + 'used': parseInt(line[2]) * 1024, + 'use': parseFloat((100.0 * line[2] / line[1]).toFixed(2)), + 'mount': line[line.length - 1] + }) + } + }); + } + if (callback) { callback(data) } + resolve(data); + }); + }); + }); } exports.fsSize = fsSize; @@ -651,132 +801,273 @@ exports.fsSize = fsSize; // FS - speed function fsStats(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } - var result = { - rx : -1, - wx : -1, - rx_sec : -1, - wx_sec : -1 - }; - var bytes_read = 0; - var bytes_write = 0; - var lines; + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } - if (_linux) { + var result = { + rx: 0, + wx: 0, + tx: 0, + rx_sec: -1, + wx_sec: -1, + tx_sec: -1, + ms: 0 + }; + + if (_linux) { // exec("df -k | grep /dev/", function(error, stdout) { - exec("lsblk | grep /", function(error, stdout) { - if (!error) { - lines = stdout.toString().split('\n'); - var 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]) - } - }); + 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]) + } + }); - var output = fs_filter.join('|'); - exec("cat /proc/diskstats | egrep '" + output + "'", function (error, stdout) { - if (!error) { - lines = stdout.toString().split('\n'); - lines.forEach(function (line) { - line = line.trim(); - if (line != '') { - line = line.replace(/ +/g, " ").split(' '); + 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(' '); - bytes_read = bytes_read + parseInt(line[5]) * 512; - bytes_write = bytes_write + parseInt(line[9]) * 512; - } - }); - if (_fs_speed && _fs_speed.ms) { - var ms = Date.now() - _fs_speed.ms; - result.rx = bytes_read; - result.wx = bytes_write; - result.rx_sec = (bytes_read - _fs_speed.bytes_read) / (ms / 1000); - result.wx_sec = (bytes_write - _fs_speed.bytes_write) / (ms / 1000); - } else { - result.rx = bytes_read; - result.wx = bytes_write; - result.rx_sec = 0; - result.wx_sec = 0; - } - _fs_speed.bytes_read = bytes_read; - _fs_speed.bytes_write = bytes_write; - _fs_speed.bytes_overall = bytes_read + bytes_write; - _fs_speed.ms = Date.now(); - } - callback(result); - }) - } else callback(result); - }) - } - if (_darwin) { - exec("ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n '/IOBlockStorageDriver/,/Statistics/p' | grep 'Statistics' | tr -d [:alpha:] | tr -d [:punct:] | awk '{print $3, $10}'", function(error, stdout) { - if (!error) { - lines = stdout.toString().split('\n'); - lines.forEach(function (line) { - line = line.trim(); - if (line != '') { - line = line.split(' '); + result.rx += parseInt(line[5]) * 512; + result.wx += parseInt(line[9]) * 512; + } + }); + result.tx = result.rx + result.wx; + if (_fs_speed && _fs_speed.ms) { + 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; + } else { + result.rx_sec = -1; + result.wx_sec = -1; + result.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(); + } + 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 -d [:alpha:] | tr -d [:punct:] | awk '{print $3, $10}'", function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + line = line.trim(); + if (line != '') { + line = line.split(' '); - bytes_read = bytes_read + parseInt(line[0]); - bytes_write = bytes_write + parseInt(line[1]); - } - }); - - if (_fs_speed && _fs_speed.ms) { - var ms = Date.now() - _fs_speed.ms; - result.rx = bytes_read; - result.wx = bytes_write; - result.rx_sec = (bytes_read - _fs_speed.bytes_read) / (ms / 1000); - result.wx_sec = (bytes_write - _fs_speed.bytes_write) / (ms / 1000); - } else { - result.rx = bytes_read; - result.wx = bytes_write; - result.rx_sec = 0; - result.wx_sec = 0; - } - _fs_speed.bytes_read = bytes_read; - _fs_speed.bytes_write = bytes_write; - _fs_speed.bytes_overall = bytes_read + bytes_write; - _fs_speed.ms = Date.now(); - } - callback(result) - }) - } + result.rx += parseInt(line[0]); + result.wx += parseInt(line[1]); + } + }); + result.tx = result.rx + result.wx; + if (_fs_speed && _fs_speed.ms) { + 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; + } else { + result.rx_sec = -1; + result.wx_sec = -1; + result.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(); + } + if (callback) { callback(result) } + resolve(result); + }) + } + }); + }); } exports.fsStats = fsStats; +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); + } + + var result = { + rIO: 0, + wIO: 0, + tIO: 0, + rIO_sec: -1, + wIO_sec: -1, + tIO_sec: -1, + ms: 0 + }; + if (_linux) { + // 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(';'); + result.rIO += parseInt(stats[0]); + result.wIO += parseInt(stats[4]); + }); + result.tIO = result.rIO + result.wIO; + if (_disk_io && _disk_io.ms) { + 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; + } else { + result.rIO_sec = -1; + result.wIO_sec = -1; + result.tIO_sec = -1; + } + _disk_io.rIO = result.rIO; + _disk_io.wIO = result.wIO; + _disk_io.tIO = result.tIO; + _disk_io.ms = Date.now(); + + 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 -d [:alpha:] | tr -d [:punct:] | awk '{print $1, $11}'", function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + line = line.trim(); + if (line != '') { + line = line.split(' '); + + result.rIO += parseInt(line[0]); + result.wIO += parseInt(line[1]); + } + }); + + result.tIO = result.rIO + result.wIO; + if (_disk_io && _disk_io.ms) { + result.ms = Date.now() - _disk_io.ms; + result.rIOPS = (result.rIO - _disk_io.rIO) / (result.ms / 1000); + result.wIOPS = (result.wIO - _disk_io.wIO) / (result.ms / 1000); + result.tIOPS = result.rIOPS + result.wIOPS; + } else { + result.rIOPS = -1; + result.wIOPS = -1; + result.tIOPS = -1; + } + _disk_io.rIO = result.rIO; + _disk_io.wIO = result.wIO; + _disk_io.tIO = result.tIO; + _disk_io.ms = Date.now(); + } + if (callback) { callback(result) } + resolve(result); + }) + } + }); + }); +} + +exports.disksIO = disksIO; + // ---------------------------------------------------------------------------------- // 7. Network // ---------------------------------------------------------------------------------- +function getFirstExternalNetworkInterface() { + + let ifacename = ''; + let ifaces = os.networkInterfaces(); + + for (let dev in ifaces) { + if (ifaces.hasOwnProperty(dev)) { + ifaces[dev].forEach(function (details) { + if (details && details.internal == false) { + ifacename = ifacename || dev; + } + }) + } + } + return ifacename; +} + // -------------------------- // NET - interfaces function networkInterfaces(callback) { - var ifaces=os.networkInterfaces(); - var result = []; - for (var dev in ifaces) { - var ip4 = ''; - var ip6 = ''; - if (ifaces.hasOwnProperty(dev)) { - ifaces[dev].forEach(function(details){ - if (details.family=='IPv4') { - ip4 = details.address - } - if (details.family=='IPv6') { - ip6 = details.address - } - }); - result.push({iface : dev, ip4 : ip4, ip6 : ip6}) - } - } - callback(result); + + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + + let ifaces = os.networkInterfaces(); + let result = []; + + for (let dev in ifaces) { + let ip4 = ''; + let ip6 = ''; + if (ifaces.hasOwnProperty(dev)) { + ifaces[dev].forEach(function (details) { + if (details.family == 'IPv4') { + ip4 = details.address + } + if (details.family == 'IPv6') { + ip6 = details.address + } + }); + let internal = (ifaces[dev] && ifaces[dev][0]) ? ifaces[dev][0].internal : null; + result.push({ iface: dev, ip4: ip4, ip6: ip6, internal: internal }) + } + } + if (callback) { callback(result) } + resolve(result); + }); + }); } exports.networkInterfaces = networkInterfaces; @@ -785,96 +1076,114 @@ exports.networkInterfaces = networkInterfaces; // NET - Speed function calcNetworkSpeed(iface, rx, tx) { - var rx_sec = -1; - var tx_sec = -1; - if (_network[iface]) { - var ms = Date.now() - _network[iface].ms; - rx_sec = (rx - _network[iface].rx) / (ms / 1000); - tx_sec = (tx - _network[iface].tx) / (ms / 1000); - } else { - _network[iface] = {}; - } - _network[iface].rx = rx; - _network[iface].tx = tx; - _network[iface].ms = Date.now(); - return ({ - rx_sec : rx_sec, - tx_sec : tx_sec - }) + let rx_sec = -1; + let tx_sec = -1; + let ms = 0; + if (_network[iface] && _network[iface].ms) { + ms = Date.now() - _network[iface].ms; + rx_sec = (rx - _network[iface].rx) / (ms / 1000); + tx_sec = (tx - _network[iface].tx) / (ms / 1000); + } else { + _network[iface] = {}; + } + _network[iface].rx = rx; + _network[iface].tx = tx; + _network[iface].ms = Date.now(); + return ({ + rx_sec: rx_sec, + tx_sec: tx_sec, + ms: ms + }) } function networkStats(iface, callback) { - // fallback - if only callback is given - if (isFunction(iface) && !callback) { - callback = iface; - iface = ''; - } - iface = iface || (_darwin ? 'en0' : 'eth0'); - if (_windows) { - callback(NOT_SUPPORTED); - } + // fallback - if only callback is given + if (isFunction(iface) && !callback) { + callback = iface; + iface = ''; + } - var result = { - iface : iface, - operstate : 'unknown', - rx: 0, - tx: 0, - rx_sec : -1, - tx_sec : -1 - }; + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } - var cmd, lines, stats, speed; + _default_iface = _default_iface || getFirstExternalNetworkInterface(); + iface = iface || _default_iface; // (_darwin ? 'en0' : 'eth0'); - 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; "; - exec(cmd, function(error, stdout) { - if (!error) { - lines = stdout.toString().split('\n'); - result.operstate = lines[0].trim(); - result.rx = parseInt(lines[1]); - result.tx = parseInt(lines[2]); + let result = { + iface: iface, + operstate: 'unknown', + rx: 0, + tx: 0, + rx_sec: -1, + tx_sec: -1, + ms: 0 + }; - speed = calcNetworkSpeed(iface, result.rx, result.tx); + let cmd, lines, stats, speed; - result.rx_sec = speed.rx_sec; - result.tx_sec = speed.tx_sec; - } - callback(result); - }); - } else callback(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 -bI " + 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(' '); - result.rx = parseInt(stats[6]); - result.tx = parseInt(stats[9]); + 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; "; + exec(cmd, function (error, stdout) { + if (!error) { + lines = stdout.toString().split('\n'); + result.operstate = lines[0].trim(); + result.rx = parseInt(lines[1]); + result.tx = parseInt(lines[2]); - speed = calcNetworkSpeed(iface, result.rx, result.tx); + speed = calcNetworkSpeed(iface, result.rx, result.tx); - result.rx_sec = speed.rx_sec; - result.tx_sec = speed.tx_sec; - } - } - callback(result); - }); - }); - } + result.rx_sec = speed.rx_sec; + result.tx_sec = speed.tx_sec; + result.ms = speed.ms; + } + if (callback) { callback(result) } + resolve(result); + }); + } else { + if (callback) { callback(result) } + 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 -bI " + 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(' '); + result.rx = parseInt(stats[6]); + result.tx = parseInt(stats[9]); + + speed = calcNetworkSpeed(iface, result.rx, result.tx); + + result.rx_sec = speed.rx_sec; + result.tx_sec = speed.tx_sec; + } + } + if (callback) { callback(result) } + resolve(result); + }); + }); + } + }); + }); } exports.networkStats = networkStats; @@ -883,28 +1192,155 @@ exports.networkStats = networkStats; // NET - connections (sockets) function networkConnections(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } - var cmd = 'netstat -tun | tail -n +3 | wc -l'; - var result; - exec(cmd, function(error, stdout) { - if (!error) { - result = parseInt(stdout.toString()); - callback(result); - } else { - cmd = 'ss -tun | tail -n +2 | wc -l'; - exec(cmd, function(error, stdout) { - if (!error) { - result = parseInt(stdout.toString()); - } else { - result = -1; - } - callback(result); - }) - } - }) + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + + var result = []; + if (_linux) { + let cmd = "netstat -tuna | grep 'ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN\\|VERBUNDEN'"; + exec(cmd, function (error, stdout) { + if (!error) { + var 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'; + if (connstate) { + result.push({ + protocol: line[0], + localaddress: localip, + localport: localport, + peeraddress: peerip, + peerport: peerport, + state: connstate + }) + } + } + }); + if (callback) { + callback(result) + } + resolve(result); + } else { + cmd = "ss -tuna | grep 'ESTAB\\|SYN-SENT\\|SYN-RECV\\|FIN-WAIT1\\|FIN-WAIT2\\|TIME-WAIT\\|CLOSE\\|CLOSE-WAIT\\|LAST-ACK\\|LISTEN\\|CLOSING'"; + exec(cmd, function (error, stdout) { + + if (!error) { + var 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'; + if (connstate) { + result.push({ + protocol: line[0], + localaddress: localip, + localport: localport, + peeraddress: peerip, + peerport: peerport, + state: connstate + }) + } + } + }); + } + if (callback) { + callback(result) + } + resolve(result); + }) + } + }) + } + if (_darwin) { + let cmd = "netstat -nat | grep 'ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN'"; + exec(cmd, 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) { + result.push({ + protocol: line[0], + localaddress: localip, + localport: localport, + peeraddress: peerip, + peerport: peerport, + state: connstate + }) + } + } + }); + if (callback) { + callback(result) + } + resolve(result); + } + }) + } + }); + }); } exports.networkConnections = networkConnections; @@ -916,38 +1352,58 @@ exports.networkConnections = networkConnections; // -------------------------- // PS - current load - in % -function getLoad(callback) { - var result = {}; - var loads = os.loadavg().map(function(x) { return x / _cores; } ); - result.avgload = parseFloat((Math.max.apply(Math, loads)).toFixed(2)); - result.currentload = -1; +function getLoad() { - var cmd = (_darwin) ? "ps -caxm -o pcpu" : "ps axo pcpu"; - exec(cmd, function(error, stdout) { - if (!error) { - var lines = stdout.toString().replace(/,+/g, ".").split('\n'); - lines.shift(); - lines.pop(); - result.currentload = parseFloat(((lines.reduce(function (pv, cv) { - return pv + parseFloat(cv.trim()); - }, 0)) / _cores).toFixed(2)); - } - callback(result) - }); + return new Promise((resolve) => { + process.nextTick(() => { + let result = {}; + let loads = os.loadavg().map(function (x) { return x / _cores; }); + result.avgload = parseFloat((Math.max.apply(Math, loads)).toFixed(2)); + result.currentload = -1; + + let cmd = (_darwin) ? "ps -caxm -o pcpu" : "ps axo pcpu"; + exec(cmd, function (error, stdout) { + if (!error) { + let lines = stdout.toString().replace(/,+/g, ".").split('\n'); + lines.shift(); + lines.pop(); + result.currentload = parseFloat(((lines.reduce(function (pv, cv) { + return pv + parseFloat(cv.trim()); + }, 0)) / _cores).toFixed(2)); + } + resolve(result); + }); + }); + }); } function currentLoad(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } - if (_cores == 0) { - cores(function() { - getLoad(callback) - }) - } else { - getLoad(callback) - } + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + + if (_cores == 0) { + cores() + .then(data => { + _cores = data; + getLoad().then(result => { + if (callback) { callback(result) } + resolve(result); + }) + }) + } else { + getLoad().then(result => { + if (callback) { callback(result) } + resolve(result); + }) + } + }); + }); } exports.currentLoad = currentLoad; @@ -956,94 +1412,126 @@ exports.currentLoad = currentLoad; // PS - full load // since bootup -function getFullLoad(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } +function getFullLoad() { - var result = {}; - if (_linux) { - if (fs.existsSync('/proc/uptime')) { - var output = fs.readFileSync('/proc/uptime').toString(); - output = output.replace(/ +/g, " ").split(' '); - var uptime = parseFloat(output[0]); - var idletime = parseFloat(output[1]) / _cores; - result.fullload = (uptime - idletime) / uptime * 100.0; - callback(result); - } - } - if (_darwin) { - result.fullload = 0; - callback(result); - } + return new Promise((resolve) => { + process.nextTick(() => { + + let result = {}; + if (_linux) { + if (fs.existsSync('/proc/uptime')) { + let output = fs.readFileSync('/proc/uptime').toString(); + output = output.replace(/ +/g, " ").split(' '); + let uptime = parseFloat(output[0]); + let idletime = parseFloat(output[1]) / _cores; + result.fullload = (uptime - idletime) / uptime * 100.0; + resolve(result); + } + } + if (_darwin) { + result.fullload = 0; + resolve(result); + } + }); + }); } function fullLoad(callback) { - if (_cores == 0) { - cores(function() { - getFullLoad(callback) - }) - } else { - getFullLoad(callback) - } + + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + + if (_cores == 0) { + cores() + .then(data => { + _cores = data; + getFullLoad().then(result => { + if (callback) { callback(result) } + resolve(result); + }) + }) + } else { + getFullLoad().then(result => { + if (callback) { callback(result) } + resolve(result); + }) + } + }); + }); } exports.fullLoad = fullLoad; - // -------------------------- // 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 (isFunction(srv) && !callback) { - callback = srv; - srv = ''; - } - if (_windows) { - callback(NOT_SUPPORTED); - } + // fallback - if only callback is given + if (isFunction(srv) && !callback) { + callback = srv; + srv = ''; + } - srv = srv.trim().replace(/,+/g, " ").replace(/ +/g, " ").replace(/ +/g, "|"); - var srvs = srv.split('|'); - var comm = (_darwin) ? "ps -caxm -o pcpu,pmem,comm" : "ps axo pcpu,pmem,comm"; - var data = []; - if (srv != '' && srvs.length > 0) { - exec(comm + " | grep -v grep | egrep '" + srv + "'", function (error, stdout) { - if (!error) { - var lines = stdout.toString().replace(/ +/g, " ").replace(/,+/g, ".").split('\n'); - srvs.forEach(function (srv) { - var ps = lines.filter(function (e) { - return e.indexOf(srv) != -1 - }); - data.push({ - 'name': srv, - 'running': ps.length > 0, - '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)) - }) - }); - callback(data) - } else { - srvs.forEach(function (srv) { - data.push({ - 'name': srv, - 'running': false, - 'pcpu': 0, - 'pmem': 0 - }) - }); - callback(data) - } - }); - } else callback(data) + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + + srv = srv.trim().replace(/,+/g, " ").replace(/ +/g, " ").replace(/ +/g, "|"); + var srvs = srv.split('|'); + var comm = (_darwin) ? "ps -caxm -o pcpu,pmem,comm" : "ps axo pcpu,pmem,comm"; + var data = []; + if (srv != '' && srvs.length > 0) { + exec(comm + " | grep -v grep | egrep '" + srv + "'", function (error, stdout) { + if (!error) { + var lines = stdout.toString().replace(/ +/g, " ").replace(/,+/g, ".").split('\n'); + srvs.forEach(function (srv) { + var ps = lines.filter(function (e) { + return e.indexOf(srv) != -1 + }); + data.push({ + 'name': srv, + 'running': ps.length > 0, + '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 (callback) { callback(data) } + resolve(data); + } else { + srvs.forEach(function (srv) { + data.push({ + 'name': srv, + 'running': false, + 'pcpu': 0, + 'pmem': 0 + }) + }); + if (callback) { callback(data) } + resolve(data); + } + }); + } else { + if (callback) { callback(data) } + resolve(data); + } + }); + }); } exports.services = services; @@ -1052,48 +1540,58 @@ exports.services = services; // running processes function processes(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } - exec("ps aux | grep -v 'ps aux' | wc -l", function(error, stdout) { - var result = { - all: 0, - running: 0, - blocked: 0 - }; - if (!error) { - result.all = parseInt(stdout.toString()); - if (_darwin) { - exec("ps axo state | grep 'R' | wc -l; ps axo state | grep 'U' | wc -l", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); - result.running = parseInt(lines[0]); - result.blocked = parseInt(lines[1]); - } - callback(result); - }) - } - if (_linux) { - exec("cat /proc/stat | grep procs_", function(error, stdout) { - if (!error) { - var lines = stdout.toString().split('\n'); - lines.forEach(function(line) { - if (line.toUpperCase().indexOf('PROCS_RUNNING') != -1) { - result.running = parseInt(line.replace(/ +/g, " ").split(' ')[1]); - } - if (line.toUpperCase().indexOf('PROCS_BLOCKED') != -1) { - result.blocked = parseInt(line.replace(/ +/g, " ").split(' ')[1]); - } - }) - } - callback(result); - }) - } - } else { - callback(result); - } - }); + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + + var result = { + all: 0, + running: 0, + blocked: 0 + }; + exec("ps aux | grep -v 'ps aux' | wc -l", function (error, stdout) { + if (!error) { + result.all = parseInt(stdout.toString()); + if (_darwin) { + exec("ps axo state | grep 'R' | wc -l; ps axo state | grep 'U' | wc -l", function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + result.running = parseInt(lines[0]); + result.blocked = parseInt(lines[1]); + } + if (callback) { callback(result) } + resolve(result); + }) + } + if (_linux) { + exec("cat /proc/stat | grep procs_", function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + if (line.toUpperCase().indexOf('PROCS_RUNNING') != -1) { + result.running = parseInt(line.replace(/ +/g, " ").split(' ')[1]); + } + if (line.toUpperCase().indexOf('PROCS_BLOCKED') != -1) { + result.blocked = parseInt(line.replace(/ +/g, " ").split(' ')[1]); + } + }) + } + if (callback) { callback(result) } + resolve(result); + }) + } + } else { + if (callback) { callback(result) } + resolve(result); + } + }); + }); + }); } exports.processes = processes; @@ -1104,45 +1602,55 @@ exports.processes = processes; // (PID, CPU-Usage %, Mem-Usage %) function processLoad(proc, callback) { - // fallback - if only callback is given - if (isFunction(proc) && !callback) { - callback = proc; - proc = ''; - } - if (_windows) { - callback(NOT_SUPPORTED); - } + // fallback - if only callback is given + if (isFunction(proc) && !callback) { + callback = proc; + proc = ''; + } - var result = { - 'proc' : proc, - 'pid' : -1, - 'cpu' : 0, - 'mem' : 0 - }; + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } - if (proc) { - exec("ps aux | grep " + proc + " | grep -v grep", function(error, stdout) { - if (!error) { - var data = stdout.replace(/ +/g, " ").split(' '); + var result = { + 'proc': proc, + 'pid': -1, + 'cpu': 0, + 'mem': 0 + }; - if (data.length > 2) { - result = { - 'proc' : proc, - 'pid' : data[1], - 'cpu' : parseFloat(data[2].replace(',', '.')), - 'mem' : parseFloat(data[3].replace(',', '.')) - } - } - } - callback(result); - }); - } else callback(result); + if (proc) { + exec("ps aux | grep " + proc + " | grep -v grep", function (error, stdout) { + if (!error) { + let data = stdout.replace(/ +/g, " ").split(' '); + + if (data.length > 2) { + result = { + 'proc': proc, + 'pid': data[1], + 'cpu': parseFloat(data[2].replace(',', '.')), + 'mem': parseFloat(data[3].replace(',', '.')) + } + } + } + if (callback) { callback(result) } + resolve(result); + }); + } else { + if (callback) { callback(result) } + resolve(result); + } + }); + }); } exports.processLoad = processLoad; - // ---------------------------------------------------------------------------------- // 9. Users/Sessions // ---------------------------------------------------------------------------------- @@ -1151,17 +1659,147 @@ exports.processLoad = processLoad; // array of users online = sessions function users(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } - var result = []; - exec("users", function(error, stdout) { - if (!error) { - result = stdout.toString().replace(/ +/g, " ").replace(/\n+/g, " ").trim().split(' ').filter(function(e) {return e.trim() !== ''}); - } - callback(result); - }); + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + + var result = []; + var result_who = []; + var result_w = {}; + var w_first = true; + var w_header = []; + var w_pos = []; + var w_headerline = ''; + var who_line = {}; + + // linux + if (_linux) { + exec("who --ips; echo '---'; w | tail -n +2", function (error, stdout) { + if (!error) { + // lines / split + var lines = stdout.toString().split('\n'); + var is_whopart = true; + lines.forEach(function (line) { + if (line == '---') { + is_whopart = false; + } else { + var 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] : '' + }) + } else { + // w part + if (w_first) { // header + w_header = l; + w_headerline = line; + w_header.forEach(function(item) { + w_pos.push(line.indexOf(item)) + }); + w_first = false; + // console.log(w_pos); + // console.log(result_who); + } 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).trim(); + result_w.command = line.substring(w_pos[7], 1000).trim(); + // console.log(result_w); + // 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 (callback) { callback(result) } + resolve(result); + } else { + if (callback) { callback(result) } + resolve(result); + } + }); + } + + if (_darwin) { + exec("who; echo '---'; w -ih", function (error, stdout) { + if (!error) { + // lines / split + var lines = stdout.toString().split('\n'); + var is_whopart = true; + lines.forEach(function (line) { + if (line == '---') { + is_whopart = false; + } else { + var 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 + }) + } + } + } + }); + if (callback) { callback(result) } + resolve(result); + } else { + if (callback) { callback(result) } + resolve(result); + } + }); + } + + + }); + }); } exports.users = users; @@ -1175,30 +1813,38 @@ exports.users = users; function inetChecksite(url, callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } - var result = { - url: url, - ok : false, - status: 404, - ms : -1 - }; - if (url && (isFunction(callback))) { - var t = Date.now(); - var args = " -I --connect-timeout 5 -m 5 " + url + " 2>/dev/null | head -n 1 | cut -d ' ' -f2"; - var cmd = "curl"; - exec(cmd + args, function(error, stdout) { - var 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); - callback(result); - }) - } else { - callback(result) - } + var result = { + url: url, + ok: false, + status: 404, + ms: -1 + }; + if (url) { + var t = Date.now(); + 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); + }) + } else { + if (callback) { callback(result) } + resolve(result); + } + }); + }); } exports.inetChecksite = inetChecksite; @@ -1206,27 +1852,43 @@ exports.inetChecksite = inetChecksite; // -------------------------- // check inet latency -function inetLatency(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } +function inetLatency(host, callback) { - var t = Date.now(); - var cmd; - if (_linux) { - cmd = "ping -c 2 -w 3 8.8.8.8 | grep rtt | cut -d'/' -f4 | awk '{ print $3 }'"; - } - if (_darwin) { - cmd = "ping -c 2 -t 3 8.8.8.8 | grep avg | cut -d'/' -f4 | awk '{ print $3 }'"; - } + // fallback - if only callback is given + if (isFunction(host) && !callback) { + callback = host; + host = ''; + } - exec(cmd, function(error, stdout) { - if (!error) { - callback(parseFloat(stdout.toString())); - } else { - callback(-1) - } - }) + host = host || '8.8.8.8'; + + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } + + var t = Date.now(); + let cmd; + if (_linux) { + cmd = "ping -c 2 -w 3 " + host + " | grep rtt | cut -d'/' -f4 | awk '{ print $3 }'"; + } + if (_darwin) { + cmd = "ping -c 2 -t 3 " + host + " | grep avg | cut -d'/' -f4 | awk '{ print $3 }'"; + } + + exec(cmd, function (error, stdout) { + let result = -1; + if (!error) { + result = parseFloat(stdout.toString()); + } + if (callback) { callback(result) } + resolve(result); + }) + }); + }); } exports.inetLatency = inetLatency; @@ -1238,29 +1900,36 @@ exports.inetLatency = inetLatency; // -------------------------- // get static data - they should not change until restarted - function getStaticData(callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } - var data = {}; + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } - data.version = version(); + var data = {}; - system(function(res) { - data.system = res; - osInfo(function(res) { - data.os = res; - cpu(function(res) { - data.cpu = res; - networkInterfaces(function(res) { - data.net = res; - callback(data); - }) - }) - }) - }) + data.version = version(); + + system().then(res => { + data.system = res; + osInfo().then(res => { + data.os = res; + cpu().then(res => { + data.cpu = res; + networkInterfaces().then(res => { + data.net = res; + if (callback) { callback(data) } + resolve(data); + }) + }) + }) + }) + }); + }); } exports.getStaticData = getStaticData; @@ -1271,61 +1940,123 @@ exports.getStaticData = getStaticData; // -------------------------- // 2 additional parameters needed // - srv: comma separated list of services to monitor e.g. "mysql, apache, postgresql" -// - network: define network for which you like to monitor network speed e.g. "eth0" +// - iface: define network interface for which you like to monitor network speed e.g. "eth0" -function getDynamicData(callback, srv, network) { +function getDynamicData(srv, iface, callback) { - if (_windows) { - callback(NOT_SUPPORTED); - } + if (isFunction(iface)) { + callback = iface; + iface = ''; + } + if (isFunction(srv)) { + callback = srv; + srv = ''; + } - network = network || (_darwin ? 'en0' : 'eth0'); - srv = srv || ''; + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } - var data = {}; + iface = iface || getFirstExternalNetworkInterface(); + srv = srv || ''; - // get time - data.time = time(); - data.node = process.versions.node; - data.v8 = process.versions.v8; + // use closure to track ƒ completion + var functionProcessed = (function () { + var totalFunctions = 13; - cpuCurrentspeed(function(res) { - data.cpuCurrentspeed = res; - users(function(res) { - data.users = res; - processes(function(res) { - data.processes = res; - currentLoad(function(res) { - data.currentLoad = res; - cpuTemperature(function(res) { - data.temp = res; - networkStats(network, function(res) { - data.networkStats = res; - networkConnections(function(res) { - data.networkConnections = res; - mem(function(res) { - data.mem = res; - services(srv, function(res) { - data.services = res; - fsSize(function(res) { - data.fsSize = res; - fsStats(function(res) { - data.fsStats=res; - inetLatency(function(res) { - data.inetLatency = res; - callback(data); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); + return function () { + if (--totalFunctions === 0) { + if (callback) { callback(data) } + resolve(data); + } + }; + })(); + + // var totalFunctions = 12; + // function functionProcessed() { + // if (--totalFunctions === 0) { + // if (callback) { callback(data) } + // resolve(data); + // } + // } + + var data = {}; + + // get time + data.time = time(); + data.node = process.versions.node; + data.v8 = process.versions.v8; + + cpuCurrentspeed().then(res => { + data.cpuCurrentspeed = res; + functionProcessed(); + }); + + users().then(res => { + data.users = res; + functionProcessed(); + }); + + processes().then(res => { + data.processes = res; + functionProcessed(); + }); + + currentLoad().then(res => { + data.currentLoad = res; + functionProcessed(); + }); + + cpuTemperature().then(res => { + data.temp = res; + functionProcessed(); + }); + + networkStats(iface).then(res => { + data.networkStats = res; + functionProcessed(); + }); + + networkConnections().then(res => { + data.networkConnections = res; + functionProcessed(); + }); + + mem().then(res => { + data.mem = res; + functionProcessed(); + }); + + services(srv).then(res => { + data.services = res; + functionProcessed(); + }); + + fsSize().then(res => { + data.fsSize = res; + functionProcessed(); + }); + + fsStats().then(res => { + data.fsStats = res; + functionProcessed(); + }); + + disksIO().then(res => { + data.disksIO = res; + functionProcessed(); + }); + + inetLatency().then(res => { + data.inetLatency = res; + functionProcessed(); + }); + }); + }); } exports.getDynamicData = getDynamicData; @@ -1335,26 +2066,34 @@ exports.getDynamicData = getDynamicData; // -------------------------- // 2 additional parameters needed // - srv: comma separated list of services to monitor e.g. "mysql, apache, postgresql" -// - network: define network for which you like to monitor network speed e.g. "eth0" +// - iface: define network interface for which you like to monitor network speed e.g. "eth0" -function getAllData(callback, srv, network) { - if (_windows) { - callback(NOT_SUPPORTED); - } +function getAllData(srv, iface, callback) { - var data = {}; + return new Promise((resolve, reject) => { + process.nextTick(() => { + if (_windows) { + let error = new Error(NOT_SUPPORTED); + if (callback) { callback(NOT_SUPPORTED) } + reject(error); + } - getStaticData(function(res) { - data = res; - getDynamicData(function(res) { - for(var key in res) { - if (res.hasOwnProperty(key)) { - data[key]=res[key]; - } - } - callback(data); - }, srv, network); - }) + var data = {}; + + getStaticData().then(res => { + data = res; + getDynamicData(srv, iface).then(res => { + for (var key in res) { + if (res.hasOwnProperty(key)) { + data[key] = res[key]; + } + } + if (callback) { callback(data) } + resolve(data); + }); + }) + }); + }); } exports.getAllData = getAllData; diff --git a/package.json b/package.json index 40202fa..dd53464 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,6 @@ "linux" ], "engines": { - "node": ">=0.10" + "node": ">=4.0.0" } }