Initial commit
This commit is contained in:
commit
c22caed446
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules/
|
363
package-lock.json
generated
Normal file
363
package-lock.json
generated
Normal file
@ -0,0 +1,363 @@
|
||||
{
|
||||
"name": "quickstatus",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"accepts": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
|
||||
"integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
|
||||
"requires": {
|
||||
"mime-types": "~2.1.18",
|
||||
"negotiator": "0.6.1"
|
||||
}
|
||||
},
|
||||
"array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.18.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz",
|
||||
"integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=",
|
||||
"requires": {
|
||||
"bytes": "3.0.0",
|
||||
"content-type": "~1.0.4",
|
||||
"debug": "2.6.9",
|
||||
"depd": "~1.1.2",
|
||||
"http-errors": "~1.6.3",
|
||||
"iconv-lite": "0.4.23",
|
||||
"on-finished": "~2.3.0",
|
||||
"qs": "6.5.2",
|
||||
"raw-body": "2.3.3",
|
||||
"type-is": "~1.6.16"
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
||||
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
|
||||
},
|
||||
"content-disposition": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
|
||||
"integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
|
||||
},
|
||||
"content-type": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
|
||||
},
|
||||
"cookie": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
|
||||
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
|
||||
},
|
||||
"cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"depd": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
|
||||
},
|
||||
"destroy": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
||||
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
|
||||
},
|
||||
"encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
|
||||
},
|
||||
"escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
|
||||
},
|
||||
"etag": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
|
||||
},
|
||||
"express": {
|
||||
"version": "4.16.4",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz",
|
||||
"integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==",
|
||||
"requires": {
|
||||
"accepts": "~1.3.5",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.18.3",
|
||||
"content-disposition": "0.5.2",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.3.1",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "~1.1.2",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "1.1.1",
|
||||
"fresh": "0.5.2",
|
||||
"merge-descriptors": "1.0.1",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "~2.3.0",
|
||||
"parseurl": "~1.3.2",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"proxy-addr": "~2.0.4",
|
||||
"qs": "6.5.2",
|
||||
"range-parser": "~1.2.0",
|
||||
"safe-buffer": "5.1.2",
|
||||
"send": "0.16.2",
|
||||
"serve-static": "1.13.2",
|
||||
"setprototypeof": "1.1.0",
|
||||
"statuses": "~1.4.0",
|
||||
"type-is": "~1.6.16",
|
||||
"utils-merge": "1.0.1",
|
||||
"vary": "~1.1.2"
|
||||
}
|
||||
},
|
||||
"finalhandler": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
|
||||
"integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
|
||||
"requires": {
|
||||
"debug": "2.6.9",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"on-finished": "~2.3.0",
|
||||
"parseurl": "~1.3.2",
|
||||
"statuses": "~1.4.0",
|
||||
"unpipe": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"forwarded": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
||||
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
|
||||
},
|
||||
"fresh": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
|
||||
},
|
||||
"http-errors": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
|
||||
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
|
||||
"requires": {
|
||||
"depd": "~1.1.2",
|
||||
"inherits": "2.0.3",
|
||||
"setprototypeof": "1.1.0",
|
||||
"statuses": ">= 1.4.0 < 2"
|
||||
}
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.23",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
|
||||
"integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
},
|
||||
"ipaddr.js": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz",
|
||||
"integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4="
|
||||
},
|
||||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
||||
},
|
||||
"merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
|
||||
},
|
||||
"methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
|
||||
"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.38.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz",
|
||||
"integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.22",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz",
|
||||
"integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==",
|
||||
"requires": {
|
||||
"mime-db": "~1.38.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"negotiator": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
|
||||
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
|
||||
},
|
||||
"node-os-utils": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/node-os-utils/-/node-os-utils-1.0.7.tgz",
|
||||
"integrity": "sha1-Q6+sBpSwTRRoIN8EkEWPzdBxBAM="
|
||||
},
|
||||
"on-finished": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
|
||||
"requires": {
|
||||
"ee-first": "1.1.1"
|
||||
}
|
||||
},
|
||||
"parseurl": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
|
||||
"integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
||||
},
|
||||
"proxy-addr": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz",
|
||||
"integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==",
|
||||
"requires": {
|
||||
"forwarded": "~0.1.2",
|
||||
"ipaddr.js": "1.8.0"
|
||||
}
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"range-parser": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
|
||||
"integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz",
|
||||
"integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==",
|
||||
"requires": {
|
||||
"bytes": "3.0.0",
|
||||
"http-errors": "1.6.3",
|
||||
"iconv-lite": "0.4.23",
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"send": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
|
||||
"integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
|
||||
"requires": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "~1.1.2",
|
||||
"destroy": "~1.0.4",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "~1.6.2",
|
||||
"mime": "1.4.1",
|
||||
"ms": "2.0.0",
|
||||
"on-finished": "~2.3.0",
|
||||
"range-parser": "~1.2.0",
|
||||
"statuses": "~1.4.0"
|
||||
}
|
||||
},
|
||||
"serve-static": {
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
|
||||
"integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
|
||||
"requires": {
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.2",
|
||||
"send": "0.16.2"
|
||||
}
|
||||
},
|
||||
"setprototypeof": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
|
||||
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
|
||||
},
|
||||
"statuses": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
|
||||
"integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
|
||||
},
|
||||
"type-is": {
|
||||
"version": "1.6.16",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
|
||||
"integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
|
||||
"requires": {
|
||||
"media-typer": "0.3.0",
|
||||
"mime-types": "~2.1.18"
|
||||
}
|
||||
},
|
||||
"unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||
},
|
||||
"utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
|
||||
}
|
||||
}
|
||||
}
|
16
package.json
Normal file
16
package.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "quickstatus",
|
||||
"version": "1.0.0",
|
||||
"description": "Get system status in JSON format",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"output": "node system.js"
|
||||
},
|
||||
"private": true,
|
||||
"license": "CC0",
|
||||
"dependencies": {
|
||||
"express": "^4.16.4",
|
||||
"node-os-utils": "^1.0.7"
|
||||
}
|
||||
}
|
20
public/dark-theme.css
Normal file
20
public/dark-theme.css
Normal file
@ -0,0 +1,20 @@
|
||||
body {
|
||||
background-color: #00060e;
|
||||
}
|
||||
.infobox {
|
||||
color: #ddd;
|
||||
}
|
||||
.infobox .header {
|
||||
background-color: #393939;
|
||||
border: 1px solid #454545;
|
||||
}
|
||||
.infobox .content {
|
||||
background-color: #242424;
|
||||
border: 1px solid #454545;
|
||||
}
|
||||
.bar-inner {
|
||||
background-color: #181818;
|
||||
}
|
||||
.bar-progress {
|
||||
background-color: #00626e;
|
||||
}
|
87
public/index.css
Normal file
87
public/index.css
Normal file
@ -0,0 +1,87 @@
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: sans-serif, sans;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
#app {
|
||||
margin: 10px 120px;
|
||||
}
|
||||
h1,h2,h3,h4 {
|
||||
margin: 0;
|
||||
}
|
||||
.infobox {
|
||||
margin: 5px;
|
||||
}
|
||||
.infobox .header {
|
||||
background-color: #f3f3f3;
|
||||
padding: 15px;
|
||||
/*border-radius: 10px 10px 0 0;*/
|
||||
border: 1px solid #ddd;
|
||||
border-bottom: 0;
|
||||
}
|
||||
.infobox .content {
|
||||
padding: 10px;
|
||||
background-color: #ececec;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
.infobox-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.infobox-row .infobox {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.row {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.row label {
|
||||
min-width: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
.bar-inner {
|
||||
height: 40px;
|
||||
background-color: #ddd;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.bar-progress {
|
||||
height: 40px;
|
||||
background-color: #00c9e1;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.bar-stats {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.bar-stats span {
|
||||
flex-grow: 1;
|
||||
color: #9c9c9c;
|
||||
}
|
||||
.bar-stats .stat-now {
|
||||
text-align: center;
|
||||
}
|
||||
.bar-stats .stat-high {
|
||||
text-align: right;
|
||||
}
|
||||
.ip-addr {
|
||||
display: block;
|
||||
}
|
||||
.sec-info {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.disks .disk {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@media only screen and (max-width: 800px) {
|
||||
#app {
|
||||
margin: 15px;
|
||||
}
|
||||
.infobox-row {
|
||||
display: block;
|
||||
}
|
||||
.infobox {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
16
public/index.html
Normal file
16
public/index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" type="text/css" href="index.css">
|
||||
<link rel="stylesheet" type="text/css" href="dark-theme.css">
|
||||
<title>Please Wait..</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h1>Gathering the latest information, please wait..</h1>
|
||||
</div>
|
||||
<script src="index.js"></script>
|
||||
</body>
|
||||
</html>
|
203
public/index.js
Normal file
203
public/index.js
Normal file
@ -0,0 +1,203 @@
|
||||
(function () {
|
||||
let app = document.getElementById('app')
|
||||
|
||||
function httpGet (url) {
|
||||
let request = new XMLHttpRequest()
|
||||
return new Promise(function (resolve, reject) {
|
||||
request.onreadystatechange = function () {
|
||||
if (this.readyState === 4) {
|
||||
if (this.status === 200) {
|
||||
resolve(this.responseText)
|
||||
} else if (this.response == null && this.status === 0) {
|
||||
reject(new Error('The status server appears to be offile.'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request.open("GET", url, true)
|
||||
request.send(null)
|
||||
})
|
||||
}
|
||||
|
||||
function bytesToSize (bytes) {
|
||||
let sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
|
||||
if (bytes == 0) return '0 Byte'
|
||||
let i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))
|
||||
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]
|
||||
}
|
||||
|
||||
// Add a zero in front of single-digit numbers
|
||||
function zf (v) {
|
||||
if (v > 9) {
|
||||
return '' + v
|
||||
} else {
|
||||
return '0' + v
|
||||
}
|
||||
}
|
||||
|
||||
// Convert seconds into years days hours minutes seconds(.milliseconds)
|
||||
function readableTime (timems, ignoreMs) {
|
||||
var time = timems | 0
|
||||
var ms = ignoreMs ? '' : '.' + zf((timems * 100) % 100 | 0)
|
||||
if (time < 60) return zf(time) + ms + 's'
|
||||
else if (time < 3600) return zf(time / 60 | 0) + 'm ' + zf(time % 60) + ms + 's'
|
||||
else if (time < 86400) return zf(time / 3600 | 0) + 'h ' + zf((time % 3600) / 60 | 0) + 'm ' + zf((time % 3600) % 60) + ms + 's'
|
||||
else if (time < 31536000) return (time / 86400 | 0) + 'd ' + zf((time % 86400) / 3600 | 0) + 'h ' + zf((time % 3600) / 60 | 0) + 'm ' + zf((time % 3600) % 60) + 's'
|
||||
else return (time / 31536000 | 0) + 'y ' + zf((time % 31536000) / 86400 | 0) + 'd ' + zf((time % 86400) / 3600 | 0) + 'h ' + zf((time % 3600) / 60 | 0) + 'm ' + zf((time % 3600) % 60) + 's'
|
||||
}
|
||||
|
||||
function e (element, content, cl) {
|
||||
let el = document.createElement(element)
|
||||
if (cl) el.className = cl
|
||||
el.innerHTML = content
|
||||
return el.outerHTML
|
||||
}
|
||||
|
||||
function box (type, content) {
|
||||
return e('div', content, type)
|
||||
}
|
||||
|
||||
function bar (metric, value, percentage, low, high) {
|
||||
return box('bar-outer',
|
||||
e('span', metric, 'bar-name') +
|
||||
box('bar-inner',
|
||||
'<div class="bar-progress" style="width: ' + percentage + '%;"></div>'
|
||||
) +
|
||||
box('bar-stats',
|
||||
e('span', low, 'stat-low') +
|
||||
e('span', value, 'stat-now') +
|
||||
e('span', high, 'stat-high')
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
function renderPage (data) {
|
||||
let title = 'Welcome to ' + data.hostname + ' on ' + data.kernel
|
||||
document.title = title
|
||||
|
||||
app.innerHTML = ''
|
||||
app.innerHTML += box('infobox-row',
|
||||
box('general infobox',
|
||||
box('header',
|
||||
e('h2', 'General')
|
||||
) +
|
||||
box('content',
|
||||
box('row',
|
||||
e('label', 'Hostname') +
|
||||
e('span', data.hostname)
|
||||
) + box('row',
|
||||
e('label', 'Uptime') +
|
||||
e('span', readableTime(data.uptime))
|
||||
) + box('row',
|
||||
e('label', 'Kernel version') +
|
||||
e('span', data.kernel)
|
||||
) + box('row',
|
||||
e('label', 'Processes') +
|
||||
e('span', data.cpu.processes)
|
||||
)
|
||||
)
|
||||
) +
|
||||
|
||||
// CPU usage
|
||||
box('cpu infobox',
|
||||
box('header',
|
||||
e('h2', 'CPU')
|
||||
) +
|
||||
box('content',
|
||||
box('row',
|
||||
e('label', 'Num. cores') +
|
||||
e('span', data.cpu.count)
|
||||
) +
|
||||
box('row',
|
||||
e('label', 'Usage') +
|
||||
e('span', Math.floor(data.cpu.usage) + ' %')
|
||||
) + box('row',
|
||||
e('label', 'Load averages') +
|
||||
e('span', data.cpu.loadAverage[0].toFixed(2) + ', ' + data.cpu.loadAverage[1].toFixed(2) + ', ' + data.cpu.loadAverage[2].toFixed(2))
|
||||
)
|
||||
)
|
||||
))
|
||||
|
||||
// Memory usage
|
||||
let memuse = (data.memory.total - data.memory.free)
|
||||
app.innerHTML += box('memory infobox',
|
||||
box('header',
|
||||
e('h2', 'Memory')
|
||||
) +
|
||||
box('content',
|
||||
bar('Memory usage', bytesToSize(memuse), memuse * 100 / data.memory.total, '0 Bytes', bytesToSize(data.memory.total))
|
||||
)
|
||||
)
|
||||
|
||||
// Network interfaces
|
||||
let interfaces = ''
|
||||
for (let int in data.network) {
|
||||
if (int === 'lo') continue
|
||||
let iface = data.network[int]
|
||||
let ips = []
|
||||
for (let ip in iface.addresses) {
|
||||
ips.push(e('span', iface.addresses[ip], 'ip-addr'))
|
||||
}
|
||||
interfaces += box('interface',
|
||||
e('h3', int) +
|
||||
ips.join('') +
|
||||
e('h4', 'Bandwidth', 'sec-info') +
|
||||
box('row',
|
||||
e('label', 'Download') +
|
||||
e('span', bytesToSize(iface.download))
|
||||
) + box('row',
|
||||
e('label', 'Upload') +
|
||||
e('span', bytesToSize(iface.upload))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Disks
|
||||
let disks = ''
|
||||
for (let mount in data.disk) {
|
||||
let disk = data.disk[mount]
|
||||
disks += box('disk',
|
||||
e('h3', 'Mounted on ' + mount) +
|
||||
box('row',
|
||||
e('label', 'Free space') +
|
||||
e('span', disk.freeGb + ' GB')
|
||||
) +
|
||||
bar('Disk usage', disk.usedGb + ' GB', disk.usedPercentage, '0 GB', disk.totalGb + ' GB')
|
||||
)
|
||||
}
|
||||
|
||||
app.innerHTML += box('infobox-row',
|
||||
box('network infobox',
|
||||
box('header',
|
||||
e('h2', 'Network Interfaces')
|
||||
) +
|
||||
box('content',
|
||||
box('interfaces', interfaces)
|
||||
)
|
||||
)+
|
||||
|
||||
box('disk infobox',
|
||||
box('header',
|
||||
e('h2', 'Disk Drives')
|
||||
) +
|
||||
box('content',
|
||||
box('disks', disks)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
function update () {
|
||||
httpGet('/status').then(function (data) {
|
||||
try {
|
||||
renderPage(JSON.parse(data))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}, function (e) {
|
||||
console.error(e)
|
||||
})
|
||||
}
|
||||
|
||||
update()
|
||||
})()
|
41
server.js
Normal file
41
server.js
Normal file
@ -0,0 +1,41 @@
|
||||
const express = require('express')
|
||||
const cprog = require('child_process')
|
||||
const path = require('path')
|
||||
|
||||
const app = express()
|
||||
const port = process.env.PORT || 8432
|
||||
|
||||
/* Information segment */
|
||||
|
||||
let info = {}
|
||||
let infoTimer
|
||||
|
||||
async function requestInfo () {
|
||||
return new Promise((resolve, reject) => {
|
||||
let proc = cprog.exec('node ' + path.join(__dirname, 'system.js'), (err, stdout) => {
|
||||
if (err) return reject(err)
|
||||
resolve(JSON.parse(stdout))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function update () {
|
||||
requestInfo().then((newInfo) => {
|
||||
info = newInfo
|
||||
}).catch(e => console.error(e))
|
||||
}
|
||||
|
||||
infoTimer = setInterval(update, 8000)
|
||||
update()
|
||||
|
||||
/* Web server segment */
|
||||
|
||||
app.use('/status', function (req, res) {
|
||||
res.jsonp(info)
|
||||
})
|
||||
|
||||
app.use('/', express.static(path.join(__dirname, 'public')))
|
||||
|
||||
app.listen(port, function (argument) {
|
||||
console.log('Listening on', port)
|
||||
})
|
86
system.js
Normal file
86
system.js
Normal file
@ -0,0 +1,86 @@
|
||||
const fs = require('fs')
|
||||
const util = require('util')
|
||||
const os = require('os')
|
||||
const osu = require('node-os-utils')
|
||||
|
||||
let disks = ['/']
|
||||
|
||||
// Get disks from environment variable
|
||||
let denv = process.env.SHOW_DISKS
|
||||
if (denv) {
|
||||
try {
|
||||
disks = JSON.parse(denv)
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
}
|
||||
|
||||
async function diskInfo () {
|
||||
let result = {}
|
||||
for (let i in disks) {
|
||||
let info = await osu.drive.info(disks[i])
|
||||
result[disks[i]] = info
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
async function networkInfo () {
|
||||
let interfaces = {}
|
||||
let all = os.networkInterfaces()
|
||||
for (let iface in all) {
|
||||
let ips = all[iface]
|
||||
interfaces[iface] = {
|
||||
addresses: [],
|
||||
upload: null,
|
||||
download: null,
|
||||
}
|
||||
for (let i in ips) {
|
||||
interfaces[iface].addresses.push(ips[i].address)
|
||||
}
|
||||
}
|
||||
|
||||
// Interface usage statistics
|
||||
let data = await osu.netstat.stats()
|
||||
for (let p in data) {
|
||||
let ifa = data[p]
|
||||
let dt = interfaces[ifa.interface]
|
||||
if (!dt) continue
|
||||
dt.upload = ifa.outputBytes
|
||||
dt.download = ifa.inputBytes
|
||||
}
|
||||
|
||||
return interfaces
|
||||
}
|
||||
|
||||
async function cpuInfo () {
|
||||
return {
|
||||
usage: await osu.cpu.usage(),
|
||||
loadAverage: os.loadavg(),
|
||||
count: os.cpus().length,
|
||||
processes: await osu.proc.totalProcesses()
|
||||
}
|
||||
}
|
||||
|
||||
async function memInfo () {
|
||||
let free = os.freemem()
|
||||
let total = os.totalmem()
|
||||
return {
|
||||
free: free,
|
||||
total: total,
|
||||
usage: (total - free) / total * 100
|
||||
}
|
||||
}
|
||||
|
||||
async function all () {
|
||||
return {
|
||||
hostname: os.hostname(),
|
||||
kernel: os.release(),
|
||||
uptime: os.uptime(),
|
||||
cpu: await cpuInfo(),
|
||||
memory: await memInfo(),
|
||||
network: await networkInfo(),
|
||||
disk: await diskInfo()
|
||||
}
|
||||
}
|
||||
|
||||
all().then((a) => console.log(JSON.stringify(a)))
|
Reference in New Issue
Block a user