diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3699c43..4d75fe3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -98,6 +98,7 @@ Other changes
| Version | Date | Comment |
| -------------- | -------------- | -------- |
+| 3.25.0 | 2017-08-07 | improved windows support `networkStats()`, `cpuCache()`, bug fix `getStaticData()` |
| 3.24.0 | 2017-08-05 | extended windows support `networkStats()`, `networkConnections()` |
| 3.23.7 | 2017-07-11 | bug fix `diskLayout()` |
| 3.23.6 | 2017-07-11 | added `cpuFlags()` to `getStaticData()`, bug fix `graphics()` (Win) |
diff --git a/README.md b/README.md
index 20a853a..cdd3537 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,7 @@ si.cpu()
## News and Changes
### Latest Activity
+- Version 3.25.0: improved windows support `networkStats()`, `cpuCache()`, bug fix `getStaticData()`
- Version 3.24.0: extended windows support `networkStats()`, `networkConnections()`
- Version 3.23.0: added `memLayout`, `diskLayout`, extended windows support (`inetChecksite`)
- Version 3.22.0: extended windows support (`users`, `inetLatency`)
@@ -128,8 +129,8 @@ I also created a nice little command line tool called [mmon][mmon-github-url] (
| | stepping | X | X | X | Processor Stepping |
| | revision | X | X | X | Revision |
| | cache | X | X | X | cache in bytes (object) |
-| | cache.l1d | X | X | | L1D size |
-| | cache.l1i | X | X | | L1I size |
+| | cache.l1d | X | X | | L1D (data) size |
+| | cache.l1i | X | X | | L1I (instruction) size |
| | cache.l2 | X | X | X | L2 size |
| | cache.l3 | X | X | X | L3 size |
| si.cpuFlags(cb) | : string | X | X | | CPU flags|
@@ -146,9 +147,9 @@ I also created a nice little command line tool called [mmon][mmon-github-url] (
| | main | X | X | X | main temperature |
| | cores | X | X | X | array of temperatures |
| | max | X | X | X | max temperature |
-| si.mem(cb) | {...} | X | X | X | Memory information|
-| | total | X | X | X | total memory |
-| | free | X | X | X | not used |
+| si.mem(cb) | {...} | X | X | X | Memory information (in bytes)|
+| | total | X | X | X | total memory in bytes |
+| | free | X | X | X | not used in bytes |
| | used | X | X | X | used (incl. buffers/cache) |
| | active | X | X | X | used actively (excl. buffers/cache) |
| | buffcache | X | X | | used by buffers+cache |
@@ -194,14 +195,14 @@ I also created a nice little command line tool called [mmon][mmon-github-url] (
| | controllers[0].vendor | X | X | X | e.g. ATI |
| | controllers[0].bus | X | X | X| on which bus (e.g. PCIe) |
| | controllers[0].vram | X | X | X | VRAM size (in MB) |
-| | controllers[0].vramDynamic | X | X | | true if dynamicly allocated ram |
-| | displays[0].model | X | X | | Monitor/Display Model |
+| | controllers[0].vramDynamic | X | X | X | true if dynamicly allocated ram |
+| | displays[0].model | X | X | X | Monitor/Display Model |
| | displays[0].main | X | X | | true if main monitor |
| | displays[0].builtin | X | X | | true if built in monitor |
| | displays[0].connection | X | X | | e.g. DisplayPort or HDMI |
| | displays[0].resolutionx | X | X | X | pixel horizontal |
| | displays[0].resolutiony | X | X | X | pixel vertical |
-| | displays[0].depth | X | X | X | color depth in bits |
+| | displays[0].pixeldepth | X | X | X | color depth in bits |
| | displays[0].sizex | X | X | | size in mm horizontal |
| | displays[0].sizey | X | X | | size in mm vertical |
@@ -280,9 +281,9 @@ I also created a nice little command line tool called [mmon][mmon-github-url] (
| | [0].mac | X | X | X | MAC address |
| | [0].internal | X | X | X | true if internal interface |
| si.networkInterfaceDefault(cb) | : string | X | X | X | get name of default network interface |
-| si.networkStats(iface,cb) | {...} | X | X | X | current network stats of given interface
iface parameter is optional
defaults to first external network interface
Windows: no iface, only overall stats!|
-| | iface | X | X | | interface (Windows: only overall stats)|
-| | operstate | X | X | | up / down |
+| si.networkStats(iface,cb) | {...} | X | X | X | current network stats of given interface
iface parameter is optional
defaults to first external network interface|
+| | iface | X | X | X | interface |
+| | operstate | X | X | X | up / down |
| | rx | X | X | X | received bytes overall |
| | tx | X | X | X | transferred bytes overall|
| | rx_sec | X | X | X | received bytes / second (* see notes) |
diff --git a/lib/cpu.js b/lib/cpu.js
index 170d569..6074b51 100644
--- a/lib/cpu.js
+++ b/lib/cpu.js
@@ -167,6 +167,8 @@ function getCpu() {
_cpu_speed = result.speed;
result = cpuBrandManufacturer(result);
result.revision = getValue(lines, 'revision', '=');
+ result.cache.l1d = 0;
+ result.cache.l1i = 0;
result.cache.l2 = getValue(lines, 'l2cachesize', '=');
result.cache.l3 = getValue(lines, 'l3cachesize', '=');
if (result.cache.l2) { result.cache.l2 = parseInt(result.cache.l2) * 1024}
@@ -188,7 +190,25 @@ function getCpu() {
}
}
}
- resolve(result);
+ exec("wmic path Win32_CacheMemory get CacheType,InstalledSize,Purpose", function (error, stdout) {
+ if (!error) {
+ let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0);
+ lines.forEach(function (line) {
+ if (line !== '') {
+ line = line.trim().split(/\s\s+/);
+ // L1 Instructions
+ if (line[2] === 'L1 Cache' && line[0] === '3') {
+ result.cache.l1i = parseInt(line[1], 10)
+ }
+ // L1 Data
+ if (line[2] === 'L1 Cache' && line[0] === '4') {
+ result.cache.l1d = parseInt(line[1], 10)
+ }
+ }
+ });
+ }
+ resolve(result);
+ })
})
}
});
@@ -374,13 +394,12 @@ function cpuFlags(callback) {
return new Promise((resolve, reject) => {
process.nextTick(() => {
+ let result = '';
if (_windows) {
- let error = new Error(NOT_SUPPORTED);
- if (callback) { callback(NOT_SUPPORTED) }
- reject(error);
+ if (callback) { callback(result) }
+ resolve(result);
}
- let result = '';
if (_linux) {
exec("lscpu", function (error, stdout) {
if (!error) {
@@ -474,13 +493,33 @@ function cpuCache(callback) {
exec("wmic cpu get l2cachesize, l3cachesize /value", function (error, stdout) {
if (!error) {
let lines = stdout.split('\r\n');
+ result.l1d = 0;
+ result.l1i = 0;
result.l2 = getValue(lines, 'l2cachesize', '=');
result.l3 = getValue(lines, 'l3cachesize', '=');
if (result.l2) { result.l2 = parseInt(result.l2) * 1024}
if (result.l3) { result.l3 = parseInt(result.l3) * 1024}
}
- if (callback) { callback(result) }
- resolve(result);
+ exec("wmic path Win32_CacheMemory get CacheType,InstalledSize,Purpose", function (error, stdout) {
+ if (!error) {
+ let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0);
+ lines.forEach(function (line) {
+ if (line !== '') {
+ line = line.trim().split(/\s\s+/);
+ // L1 Instructions
+ if (line[2] === 'L1 Cache' && line[0] === '3') {
+ result.l1i = parseInt(line[1], 10)
+ }
+ // L1 Data
+ if (line[2] === 'L1 Cache' && line[0] === '4') {
+ result.l1d = parseInt(line[1], 10)
+ }
+ }
+ });
+ }
+ if (callback) { callback(result) }
+ resolve(result);
+ })
})
}
});
diff --git a/lib/dockerSocket.js b/lib/dockerSocket.js
index 459ee12..fde4ceb 100644
--- a/lib/dockerSocket.js
+++ b/lib/dockerSocket.js
@@ -1,4 +1,16 @@
'use strict';
+// ==================================================================================
+// dockerSockets.js
+// ----------------------------------------------------------------------------------
+// Description: System Information - library
+// for Node.js
+// Copyright: (c) 2014 - 2017
+// Author: Sebastian Hildebrandt
+// ----------------------------------------------------------------------------------
+// License: MIT
+// ==================================================================================
+// 13. DockerSockets
+// ----------------------------------------------------------------------------------
const net = require('net');
const isWin = require('os').type() === 'Windows_NT';
diff --git a/lib/graphics.js b/lib/graphics.js
index 38afcba..6e33ee3 100644
--- a/lib/graphics.js
+++ b/lib/graphics.js
@@ -23,6 +23,9 @@ const _linux = (_platform === 'Linux');
const _darwin = (_platform === 'Darwin');
const _windows = (_platform === 'Windows_NT');
const NOT_SUPPORTED = 'not supported';
+let _resolutionx = 0;
+let _resolutiony = 0;
+let _pixeldepth = 0;
function getValue(lines, property, separator) {
separator = separator || ':';
@@ -38,6 +41,14 @@ function getValue(lines, property, separator) {
return '';
}
+function toInt(value) {
+ let result = parseInt(value,10);
+ if (isNaN(result)) {
+ result = 0;
+ }
+ return result
+}
+
function graphics(callback) {
function parseLinesDarwin(lines) {
@@ -313,7 +324,7 @@ function graphics(callback) {
}
if (_windows) {
// https://blogs.technet.microsoft.com/heyscriptingguy/2013/10/03/use-powershell-to-discover-multi-monitor-information/
- exec("wmic path win32_VideoController get AdapterCompatibility, AdapterDACType, name, PNPDeviceID, CurrentVerticalResolution, CurrentHorizontalResolution, CurrentNumberOfColors, AdapterRAM, CurrentBitsPerPixel, CurrentRefreshRate, MinRefreshRate, MaxRefreshRate /value", function (error, stdout) {
+ exec("wmic path win32_VideoController get AdapterCompatibility, AdapterDACType, name, PNPDeviceID, CurrentVerticalResolution, CurrentHorizontalResolution, CurrentNumberOfColors, AdapterRAM, CurrentBitsPerPixel, CurrentRefreshRate, MinRefreshRate, MaxRefreshRate, VideoMemoryType /value", function (error, stdout) {
if (!error) {
let csections = stdout.split(/\n\s*\n/);
result.controllers = parseLinesWindowsControllers(csections);
@@ -321,6 +332,17 @@ function graphics(callback) {
let dsections = stdout.split(/\n\s*\n/);
if (!error) {
result.displays = parseLinesWindowsDisplays(dsections);
+ if (result.controllers.length === 1 && result.displays.length === 1) {
+ if (_resolutionx && !result.displays[0].resolutionx) {
+ result.displays[0].resolutionx = _resolutionx
+ }
+ if (_resolutiony && !result.displays[0].resolutiony) {
+ result.displays[0].resolutiony = _resolutiony
+ }
+ if (_pixeldepth) {
+ result.displays[0].pixeldepth = _pixeldepth
+ }
+ }
}
if (callback) {
callback(result)
@@ -330,7 +352,6 @@ function graphics(callback) {
}
})
}
-
});
});
@@ -345,8 +366,12 @@ function graphics(callback) {
model: getValue(lines, 'name', '='),
vendor: getValue(lines, 'AdapterCompatibility', '='),
bus: getValue(lines, 'PNPDeviceID', '=').startsWith('PCI') ? 'PCI' : '',
- vram: getValue(lines, 'AdapterRAM', '=')
+ vram: getValue(lines, 'AdapterRAM', '='),
+ vramDynamic: (getValue(lines, 'VideoMemoryType', '=') === '2')
});
+ _resolutionx = toInt(getValue(lines, 'CurrentHorizontalResolution', '='));
+ _resolutiony = toInt(getValue(lines, 'CurrentVerticalResolution', '='));
+ _pixeldepth = toInt(getValue(lines, 'CurrentBitsPerPixel', '='));
}
}
}
@@ -361,8 +386,8 @@ function graphics(callback) {
let lines = sections[i].trim().split('\r\n');
displays.push({
model: getValue(lines, 'MonitorManufacturer', '='),
- resolutionx: getValue(lines, 'ScreenWidth', '='),
- resolutiony: getValue(lines, 'ScreenHeight', '=')
+ resolutionx: toInt(getValue(lines, 'ScreenWidth', '=')),
+ resolutiony: toInt(getValue(lines, 'ScreenHeight', '=')),
});
}
}
diff --git a/lib/network.js b/lib/network.js
index b51c551..8b964ca 100644
--- a/lib/network.js
+++ b/lib/network.js
@@ -28,26 +28,49 @@ const NOT_SUPPORTED = 'not supported';
let _network = {};
let _default_iface;
+function getValue(lines, property, separator) {
+ separator = separator || ':';
+ property = property.toLowerCase();
+ for (let i = 0; i < lines.length; i++) {
+ if (lines[i].toLowerCase().startsWith(property)) {
+ const parts = lines[i].split(separator);
+ if (parts.length > 1) {
+ return parts[1].trim();
+ }
+ }
+ }
+ return '';
+}
+
function getDefaultNetworkInterface() {
if (!_default_iface) {
let ifacename = '';
+ let scopeid = 9999;
if (_linux || _darwin) {
let cmd = (_linux ? "route 2>/dev/null | grep default | awk '{print $8}'" : "route get 0.0.0.0 2>/dev/null | grep interface: | awk '{print $2}'");
let result = execSync(cmd);
ifacename = result.toString().split('\n')[0];
}
- if (!ifacename) { // fallback - "first" external interface
- const sortObject = o => Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {});
+ if (!ifacename) { // fallback - "first" external interface (sorted by scopeid)
- let ifaces = sortObject(os.networkInterfaces());
+ const compare = function(a,b) {
+ if (a.scopeid < b.scopeid)
+ return -1;
+ if (a.scopeid > b.scopeid)
+ return 1;
+ return 0;
+ }
+
+ 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;
+ if (details && details.internal === false && details.scopeid && details.scopeid < scopeid) {
+ ifacename = dev;
+ scopeid = details.scopeid;
}
})
}
@@ -64,12 +87,6 @@ function networkInterfaceDefault(callback) {
return new Promise((resolve, reject) => {
process.nextTick(() => {
- if (_windows) {
- let error = new Error(NOT_SUPPORTED);
- if (callback) { callback(NOT_SUPPORTED) }
- reject(error);
- }
-
let result = getDefaultNetworkInterface();
if (callback) { callback(result) }
resolve(result);
@@ -157,6 +174,46 @@ function calcNetworkSpeed(iface, rx, tx, operstate) {
function networkStats(iface, callback) {
+ function parseLinesWindowsNics(sections){
+ let nics = [];
+ for (let i in sections) {
+ if (sections.hasOwnProperty(i)) {
+ if (sections[i].trim() !== "") {
+
+ let lines = sections[i].trim().split('\r\n');
+ let netEnabled = getValue(lines, 'NetEnabled', '=');
+ if (netEnabled) {
+ nics.push({
+ mac: getValue(lines, 'MACAddress', '=').toLowerCase(),
+ name: getValue(lines, 'Name', '=').replace(/[()\[\] ]+/g, "").toLowerCase(),
+ netEnabled: netEnabled === 'TRUE'
+ });
+ }
+ }
+ }
+ }
+ return nics;
+ }
+
+ function parseLinesWindowsPerfData(sections){
+ let perfData = [];
+ for (let i in sections) {
+ if (sections.hasOwnProperty(i)) {
+ if (sections[i].trim() !== "") {
+
+ let lines = sections[i].trim().split('\r\n');
+ perfData.push({
+ name: getValue(lines, 'Name', '=').replace(/[()\[\] ]+/g, "").toLowerCase(),
+ rx: parseInt(getValue(lines, 'BytesReceivedPersec', '='),10),
+ tx: parseInt(getValue(lines, 'BytesSentPersec', '='),10)
+ });
+ }
+ }
+ }
+ return perfData;
+ }
+
+
// fallback - if only callback is given
if (util.isFunction(iface) && !callback) {
callback = iface;
@@ -168,9 +225,6 @@ function networkStats(iface, callback) {
_default_iface = _default_iface || getDefaultNetworkInterface();
iface = iface || _default_iface; // (_darwin ? 'en0' : 'eth0');
- if (_windows) {
- iface = 'all'
- }
let result = {
iface: iface,
@@ -239,21 +293,60 @@ function networkStats(iface, callback) {
});
}
if (_windows) {
- cmd = "netstat -e";
+ // NICs
+ let perfData = [];
+ let nics = [];
+ cmd = "wmic nic get MACAddress, name, NetEnabled /value";
exec(cmd, function (error, stdout) {
- const lines = stdout.split('\r\n');
- for (let i = 0; i < lines.length; i++) {
- if (lines[i].toLowerCase().startsWith('bytes')) {
- const parts = lines[i].substr(5).trim().replace(/ +/g, " ").split(' ');
- if (parts.length > 1) {
- rx = parseInt(parts[0]);
- tx = parseInt(parts[1]);
- result = calcNetworkSpeed(iface, rx, tx, operstate);
+ if (!error) {
+ const nsections = stdout.split(/\n\s*\n/);
+ nics = parseLinesWindowsNics(nsections);
+
+ // Performance Data
+ cmd = "wmic path Win32_PerfRawData_Tcpip_NetworkInterface Get name,BytesReceivedPersec,BytesSentPersec,BytesTotalPersec /value";
+ exec(cmd, function (error, stdout) {
+ if (!error) {
+ const psections = stdout.split(/\n\s*\n/);
+ perfData = parseLinesWindowsPerfData(psections);
}
- }
+
+ // Network Interfaces
+ networkInterfaces().then(interfaces => {
+ // get mac from 'interfaces' by interfacename
+ let mac = '';
+ interfaces.forEach(detail => {
+ if (detail.iface === iface) {
+ mac = detail.mac;
+ }
+ })
+
+ // get name from 'nics' (by macadress)
+ let name = '';
+ nics.forEach(detail => {
+ if (detail.mac === mac) {
+ name = detail.name;
+ operstate = (detail.netEnabled ? 'up' : 'down')
+ }
+ })
+
+ // get bytes sent, received from perfData by name
+ rx = 0;
+ tx = 0;
+ perfData.forEach(detail => {
+ if (detail.name === name) {
+ rx = detail.rx;
+ tx = detail.tx;
+ }
+ });
+
+ if (rx && tx) {
+ result = calcNetworkSpeed(iface, parseInt(rx), parseInt(tx), operstate);
+ }
+ if (callback) { callback(result) }
+ resolve(result);
+ })
+ })
}
- if (callback) { callback(result) }
- resolve(result);
});
}
} else {
diff --git a/package.json b/package.json
index 967e02f..0dbb9ba 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,7 @@
"netstats",
"network",
"network connections",
+ "network stats",
"processes",
"users",
"internet",