Created
March 6, 2019 14:44
-
-
Save zerobias/45c0e17ac24687ba981bebea5090fe07 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//@flow | |
import _os from 'os' | |
export function platform() { | |
return process.platform | |
} | |
export function cpuCount() { | |
return _os.cpus().length | |
} | |
export function sysUptime() { | |
return ( | |
//seconds | |
_os.uptime() | |
) | |
} | |
export function processUptime() { | |
return ( | |
//seconds | |
process.uptime() | |
) | |
} | |
// Memory | |
export function freemem() { | |
return _os.freemem() / (1024 * 1024) | |
} | |
export function totalmem() { | |
return _os.totalmem() / (1024 * 1024) | |
} | |
export function freememPercentage() { | |
return _os.freemem() / _os.totalmem() | |
} | |
export function freeCommand(callback: (n: number) => any) { | |
// Only Linux | |
require('child_process').exec('free -m', (error, stdout, stderr) => { | |
const lines = stdout.split('\n') | |
const str_mem_info = lines[1].replace(/[\s\n\r]+/g, ' ') | |
const mem_info = str_mem_info.split(' ') | |
const total_mem = parseFloat(mem_info[1]) | |
const free_mem = parseFloat(mem_info[3]) | |
const buffers_mem = parseFloat(mem_info[5]) | |
const cached_mem = parseFloat(mem_info[6]) | |
const used_mem = total_mem - (free_mem + buffers_mem + cached_mem) | |
callback(used_mem - 2) | |
}) | |
} | |
// Hard Disk Drive | |
export function harddrive( | |
callback: (total: number, free: number, used: number) => any, | |
) { | |
require('child_process').exec('df -k', (error, stdout, stderr) => { | |
let total = 0 | |
let used = 0 | |
let free = 0 | |
const lines = stdout.split('\n') | |
const str_disk_info = lines[1].replace(/[\s\n\r]+/g, ' ') | |
const disk_info = str_disk_info.split(' ') | |
total = Math.ceil((disk_info[1] * 1024) / 1024 ** 2) | |
used = Math.ceil((disk_info[2] * 1024) / 1024 ** 2) | |
free = Math.ceil((disk_info[3] * 1024) / 1024 ** 2) | |
callback(total, free, used) | |
}) | |
} | |
// Return process running current | |
export function getProcesses( | |
nProcess: Function | number, | |
callback: (n: string) => any, | |
) { | |
// if nprocess is undefined then is function | |
if (typeof nProcess === 'function') { | |
callback = nProcess | |
nProcess = 0 | |
} | |
let command = `ps -eo pcpu,pmem,time,args | sort -k 1 -r | head -n${10}` | |
//command = 'ps aux | head -n '+ 11 | |
//command = 'ps aux | head -n '+ (nProcess + 1) | |
if (nProcess > 0) | |
command = `ps -eo pcpu,pmem,time,args | sort -k 1 -r | head -n${nProcess + | |
1}` | |
require('child_process').exec(command, function(error, stdout, stderr) { | |
const that = this | |
const lines = stdout.split('\n') | |
lines.shift() | |
lines.pop() | |
let result = '' | |
lines.forEach((_item, _i) => { | |
let _str = _item.replace(/[\s\n\r]+/g, ' ') | |
_str = _str.split(' ') | |
// result += _str[10]+" "+_str[9]+" "+_str[2]+" "+_str[3]+"\n"; | |
// process | |
result += `${_str[1]} ${_str[2]} ${_str[3]} ${_str[4].substring( | |
_str[4].length - 25, | |
)}\n` // process | |
}) | |
callback(result) | |
}) | |
} | |
/* | |
* Returns All the load average usage for 1, 5 or 15 minutes. | |
*/ | |
export function allLoadavg() { | |
const loads = _os.loadavg() | |
return `${loads[0].toFixed(4)},${loads[1].toFixed(4)},${loads[2].toFixed(4)}` | |
} | |
/* | |
* Returns the load average usage for 1, 5 or 15 minutes. | |
*/ | |
export function loadavg(_time?: 1 | 5 | 15) { | |
if (_time === undefined || (_time !== 5 && _time !== 15)) _time = 1 | |
const loads = _os.loadavg() | |
let v = 0 | |
if (_time == 1) v = loads[0] | |
if (_time == 5) v = loads[1] | |
if (_time == 15) v = loads[2] | |
return v | |
} | |
export function cpuFree(callback: (n: number) => any) { | |
getCPUUsage(callback, true) | |
} | |
export function cpuUsage(callback: (n: number) => any) { | |
getCPUUsage(callback, false) | |
} | |
function getCPUUsage(callback: (n: number) => any, free) { | |
const stats1 = getCPUInfo() | |
const startIdle = stats1.idle | |
const startTotal = stats1.total | |
setTimeout(() => { | |
const stats2 = getCPUInfo() | |
const endIdle = stats2.idle | |
const endTotal = stats2.total | |
const idle = endIdle - startIdle | |
const total = endTotal - startTotal | |
const perc = idle / total | |
if (free === true) callback(perc) | |
else callback(1 - perc) | |
}, 1000) | |
} | |
function getCPUInfo(callback) { | |
const cpus = _os.cpus() | |
let user = 0 | |
let nice = 0 | |
let sys = 0 | |
let idle = 0 | |
let irq = 0 | |
let total = 0 | |
//$todo | |
for (const cpu in cpus) { | |
if (!cpus.hasOwnProperty(cpu)) continue | |
user += cpus[cpu].times.user | |
nice += cpus[cpu].times.nice | |
sys += cpus[cpu].times.sys | |
irq += cpus[cpu].times.irq | |
idle += cpus[cpu].times.idle | |
} | |
total = user + nice + sys + idle + irq | |
return { | |
idle, | |
total, | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//@flow | |
import tty from 'tty' | |
import {Stream} from 'stream' | |
export default function createCharm(...args: $ReadOnlyArray<*>) { | |
let input = null | |
function setInput(s) { | |
if (input) throw new Error('multiple inputs specified') | |
else input = s | |
} | |
let output = null | |
function setOutput(s) { | |
if (output) throw new Error('multiple outputs specified') | |
else output = s | |
} | |
for (const arg of args) { | |
if (!arg) continue | |
if (arg.readable) setInput(arg) | |
else if (arg.stdin || arg.input) setInput(arg.stdin || arg.input) | |
if (arg.writable) setOutput(arg) | |
else if (arg.stdout || arg.output) setOutput(arg.stdout || arg.output) | |
} | |
if (input && typeof input.fd === 'number' && tty.isatty(input.fd)) { | |
if (process.stdin.setRawMode) { | |
//$off | |
process.stdin.setRawMode(true) | |
} else tty.setRawMode(true) | |
} | |
const charm = new Charm() | |
if (input) { | |
input.pipe(charm) | |
} | |
if (output) { | |
//$off | |
charm.pipe(output) | |
} | |
charm.once('^C', process.exit) | |
charm.once('end', () => { | |
if (input) { | |
if (typeof input.fd === 'number' && tty.isatty(input.fd)) { | |
if (process.stdin.setRawMode) { | |
//$off | |
process.stdin.setRawMode(false) | |
} else tty.setRawMode(false) | |
} | |
input.destroy() | |
} | |
}) | |
return charm | |
} | |
export class Charm extends Stream { | |
writable = true | |
readable = true | |
pending: Array<(buf: Buffer | string) => void | boolean> = [] | |
write(buf: Buffer | string) { | |
if (this.pending.length) { | |
const codes = extractCodes(buf) | |
let matched = false | |
for (let i = 0; i < codes.length; i++) { | |
for (let j = 0; j < this.pending.length; j++) { | |
const cb = this.pending[j] | |
if (cb(codes[i])) { | |
matched = true | |
this.pending.splice(j, 1) | |
break | |
} | |
} | |
} | |
if (matched) return | |
} | |
if (buf.length === 1) { | |
if (buf[0] === 3) this.emit('^C') | |
if (buf[0] === 4) this.emit('^D') | |
} | |
this.emit('data', buf) | |
return this | |
} | |
destroy() { | |
this.end() | |
} | |
end(buf?: Buffer | string) { | |
if (buf) this.write(buf) | |
this.emit('end') | |
} | |
reset(cb: void) { | |
// resets the screen on iTerm, which appears | |
// to lack support for the reset character. | |
this.write(encode('[0m')) | |
this.write(encode('[2J')) | |
this.write(encode('c')) | |
return this | |
} | |
position(...args: [number, number] | [(x: number, y: number) => any]) { | |
if (args.length === 1) { | |
const [x] = args | |
// get/set absolute coordinates | |
if (typeof x === 'function') { | |
const cb = x | |
this.pending.push((buf: Buffer | string) => { | |
if ( | |
buf[0] === 27 | |
&& buf[1] === encode.ord('[') | |
&& buf[buf.length - 1] === encode.ord('R') | |
) { | |
const pos = buf | |
.toString() | |
.slice(2, -1) | |
.split(';') | |
.map(Number) | |
cb(pos[1], pos[0]) | |
return true | |
} | |
}) | |
this.write(encode('[6n')) | |
} | |
} else if (args.length === 2) { | |
const x = args[0] | |
//$off | |
const y = args[1] | |
//$todo | |
this.write(encode(`[${Math.floor(y)};${Math.floor(x)}f`)) | |
} | |
return this | |
} | |
move(x: number, y: number) { | |
// set relative coordinates | |
const bufs = [] | |
if (y < 0) this.up(-y) | |
else if (y > 0) this.down(y) | |
if (x > 0) this.right(x) | |
else if (x < 0) this.left(-x) | |
return this | |
} | |
up(y: number = 1) { | |
this.write(encode(`[${Math.floor(y)}A`)) | |
return this | |
} | |
down(y: number = 1) { | |
this.write(encode(`[${Math.floor(y)}B`)) | |
return this | |
} | |
right(x: number = 1) { | |
this.write(encode(`[${Math.floor(x)}C`)) | |
return this | |
} | |
left(x: number = 1) { | |
this.write(encode(`[${Math.floor(x)}D`)) | |
return this | |
} | |
column(x: number) { | |
this.write(encode(`[${Math.floor(x)}G`)) | |
return this | |
} | |
push(withAttributes: boolean) { | |
this.write(encode(withAttributes ? '7' : '[s')) | |
return this | |
} | |
pop(withAttributes: boolean) { | |
this.write(encode(withAttributes ? '8' : '[u')) | |
return this | |
} | |
erase(s: 'end' | '$' | 'start' | '^' | 'line' | 'down' | 'up' | 'screen') { | |
if (s === 'end' || s === '$') { | |
this.write(encode('[K')) | |
} else if (s === 'start' || s === '^') { | |
this.write(encode('[1K')) | |
} else if (s === 'line') { | |
this.write(encode('[2K')) | |
} else if (s === 'down') { | |
this.write(encode('[J')) | |
} else if (s === 'up') { | |
this.write(encode('[1J')) | |
} else if (s === 'screen') { | |
this.write(encode('[1J')) | |
} else { | |
this.emit('error', new Error(`Unknown erase type: ${s}`)) | |
} | |
return this | |
} | |
delete(s: 'line' | 'char', n: number = 1) { | |
if (s === 'line') { | |
this.write(encode(`[${n}M`)) | |
} else if (s === 'char') { | |
this.write(encode(`[${n}M`)) | |
} else { | |
this.emit('error', new Error(`Unknown delete type: ${s}`)) | |
} | |
return this | |
} | |
insert(mode: boolean | 'line' | 'char', n: number = 1) { | |
if (mode === true) { | |
this.write(encode('[4h')) | |
} else if (mode === false) { | |
this.write(encode('[l')) | |
} else if (mode === 'line') { | |
this.write(encode(`[${n}L`)) | |
} else if (mode === 'char') { | |
this.write(encode(`[${n}@`)) | |
} else { | |
this.emit('error', new Error(`Unknown delete type: ${mode}`)) | |
} | |
return this | |
} | |
display( | |
attr: | |
| 'reset' | |
| 'bright' | |
| 'dim' | |
| 'underscore' | |
| 'blink' | |
| 'reverse' | |
| 'hidden', | |
) { | |
const c = { | |
reset: 0, | |
bright: 1, | |
dim: 2, | |
underscore: 4, | |
blink: 5, | |
reverse: 7, | |
hidden: 8, | |
}[attr] | |
if (c === undefined) { | |
this.emit('error', new Error(`Unknown attribute: ${attr}`)) | |
} | |
this.write(encode(`[${c}m`)) | |
return this | |
} | |
foreground( | |
color: | |
| number | |
| 'black' | |
| 'red' | |
| 'green' | |
| 'yellow' | |
| 'blue' | |
| 'magenta' | |
| 'cyan' | |
| 'white', | |
) { | |
if (typeof color === 'number') { | |
if (color < 0 || color >= 256) { | |
this.emit('error', new Error(`Color out of range: ${color}`)) | |
} | |
this.write(encode(`[38;5;${color}m`)) | |
} else { | |
const c = { | |
black: 30, | |
red: 31, | |
green: 32, | |
yellow: 33, | |
blue: 34, | |
magenta: 35, | |
cyan: 36, | |
white: 37, | |
}[color.toLowerCase()] | |
if (!c) this.emit('error', new Error(`Unknown color: ${color}`)) | |
this.write(encode(`[${c}m`)) | |
} | |
return this | |
} | |
background( | |
color: | |
| number | |
| 'black' | |
| 'red' | |
| 'green' | |
| 'yellow' | |
| 'blue' | |
| 'magenta' | |
| 'cyan' | |
| 'white', | |
) { | |
if (typeof color === 'number') { | |
if (color < 0 || color >= 256) { | |
this.emit('error', new Error(`Color out of range: ${color}`)) | |
} | |
this.write(encode(`[48;5;${color}m`)) | |
} else { | |
const c = { | |
black: 40, | |
red: 41, | |
green: 42, | |
yellow: 43, | |
blue: 44, | |
magenta: 45, | |
cyan: 46, | |
white: 47, | |
}[color.toLowerCase()] | |
if (!c) this.emit('error', new Error(`Unknown color: ${color}`)) | |
this.write(encode(`[${c}m`)) | |
} | |
return this | |
} | |
cursor(visible: boolean) { | |
this.write(encode(visible ? '[?25h' : '[?25l')) | |
return this | |
} | |
} | |
export function encode(xs: string | Array<number>) { | |
function bytes(s) { | |
if (typeof s === 'string') { | |
return s.split('').map(ord) | |
} else if (Array.isArray(s)) { | |
return s.reduce((acc, c) => acc.concat(bytes(c)), []) | |
} | |
return [] | |
} | |
return Buffer.from([0x1b].concat(bytes(xs))) | |
} | |
encode.ord = ord | |
function ord(c) { | |
return c.charCodeAt(0) | |
} | |
export function extractCodes(buf: Buffer | string) { | |
const codes = [] | |
let start = -1 | |
for (let i = 0; i < buf.length; i++) { | |
if (buf[i] === 27) { | |
if (start >= 0) codes.push(buf.slice(start, i)) | |
start = i | |
} else if (start >= 0 && i === buf.length - 1) { | |
codes.push(buf.slice(start)) | |
} | |
} | |
return codes | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment