raidar
Version:
NetGear RAIDar Node.js implementation
366 lines (293 loc) • 7.5 kB
JavaScript
/**
* dependencies
*/
var bytes = require('bytes')
var deprecate = require('deprecate')
/**
* each all regex matches
*
* @param {RegExp|String} regex
* @param {String} text
* @param {Function} callback
*/
function _eachRegExp (regexp, text, callback) {
// ensure regexp type
if (typeof regexp === 'string') regexp = new RegExp(regexp, 'g')
// first parse
var result = regexp.exec(text)
// each while regex match
while (result) {
// execute callback
callback(result)
// get next match
result = regexp.exec(text)
}
}
/**
* parse entity body
*
* @param {String} data
* @param {Number} [index]
* @return {Object}
*/
function _parseEntity (data, index) {
// resulting attributes
var attributes = { _index: index ? parseInt(index, 10) : 0 }
// split by "::"
data.split('::').forEach(function (attribute) {
// split attribute name and value
attribute = attribute.split('=')
// save its value
attributes[attribute[0]] = attribute[1]
})
// return attributes
return attributes
}
/**
* @class ReadyNAS
* @constructor
*
* @param {Buffer|String} ini ReadyNAS device .ini
* @param {String} [encoding] default 'uft8'
*/
function ReadyNAS (message) {
// cast buffer to string
if (message instanceof Buffer) message = message.toString('ascii')
// save message internally
this.message = message
}
/**
* get device MAC address
*
* @return {String}
*/
ReadyNAS.prototype.mac = function () {
// probably....
return this.message.substr(28, 17)
}
/**
* get device hostname
*
* @return {String}
*/
ReadyNAS.prototype.hostname = function () {
// probably....
return /\t(\S+)/.exec(this.message)[1]
}
/**
* get device IP
*
* @return {String}
*/
ReadyNAS.prototype.ip = function () {
// probably....
return /\t(\d+.\d+.\d+.\d+)\t/.exec(this.message)[1]
}
/**
* get all available entities
*
* @return {Array}
*/
ReadyNAS.prototype.getEntities = function () {
// resulting array
var entities = []
// each all matches
_eachRegExp(/(\w+)!!\d+!![^\n\t]*/g, this.message, function (entity) {
// get entity name
var name = entity[1]
// save new entities
if (entities.indexOf(name) === -1) entities.push(name)
})
// return results
return entities
}
/**
* get entity data
*
* @param {String} entity entity name
* @param {Number} [index] entity index (1 based, default non-array entities)
* @return {Object|Array}
*/
ReadyNAS.prototype.getEntity = function (entity, index) {
// set default index
if (typeof index !== 'number') index = 0
// create custom regex
var regex = new RegExp(entity + '!!' + index + '!!([^\\n\\t]*)')
// ensure entity data
if (!regex.test(this.message)) throw new Error('Entity not found')
// return parsed entity data
return _parseEntity(regex.exec(this.message)[1], index)
}
/**
* get single entity attribute
*
* @param {String} field
* @param {Number} [index]
* @param {String} attribute
* @return {*}
*/
ReadyNAS.prototype.getEntityAttribute = function (field, index, attribute) {
// handle optional index signature
if (typeof index === 'string') {
// get attribute
attribute = index
// remove index
index = undefined
}
// parse entity data
var data = this.getEntity(field, index)
// return single attribute
return data[attribute]
}
/**
* get Object representation of this device
*
* @return {Object}
*/
ReadyNAS.prototype.toJSON = function () {
// resulting array
var result = {}
// each all entities
_eachRegExp(/(\w+)!!(\d+)!!([^\n\t]*)/g, this.message, function (entity) {
// parse single entity data
var attributes = _parseEntity(entity[3], entity[2])
// save entity attributes
if (attributes._index <= 0) { // handle single entry entities
// check for previous data
if (result[entity[1]]) throw new Error('nope')
// save directly as object
result[entity[1]] = attributes
} else { // handle multiple entries entities
// ensure array
result[entity[1]] = result[entity[1]] || []
// push new entry
result[entity[1]].push(attributes)
}
})
// return serialized object
return result
}
/**
* get single disk info
*
* statuses found:
* - ok
* - warn
* - dead
*
* @param {Number} index disk index, 1 based
* @param {String} [info] 'status', 'channel', 'model', 'celsius', 'fahrenheit'
* @return {String|Number}
*/
ReadyNAS.prototype.diskInfo = function (index, attribute) {
// parse entity data
var data = this.getEntity('disk', index)
// detect request
switch (attribute) {
// extract and parse channel from description
case 'channel':
return parseInt(/Channel (\d+)/.exec(data.descr)[1], 10)
// extract HDD model from description
case 'model':
return /Channel \d+: (.*),/.exec(data.descr)[1]
// extract and parse temperature from description
case 'temp':
case 'temperature':
case 'celsius':
case 'fahrenheit':
return parseInt(/(\d+)C\/(\d+)F/.exec(data.descr)[attribute === 'fahrenheit' ? 2 : 1], 10)
// just return entity attribute
default:
case 'status':
return data.status
}
}
/**
* count disks
*
* @return {Number}
*/
ReadyNAS.prototype.diskCount = function () {
// return number of disk entities
return this.message.match(/disk!!\d+!!/g).length
}
/**
* get device serial number
*
* @return {String}
*/
ReadyNAS.prototype.serial = function () {
// get single attribute from model entity
return this.getEntityAttribute('model', 'sn')
}
/**
* get device firmware version
*
* @return {String}
*/
ReadyNAS.prototype.version = function () {
// get single attribute from model entity
return this.getEntityAttribute('model', 'fw')
}
/**
* get single RAID volume info
*
* @param {Number} index
* @param {String} [attribute] 'status', level', 'message', 'size', 'used', 'free'
* @return {String|Number}
*/
ReadyNAS.prototype.volumeInfo = function (index, attribute) {
var data = this.getEntity('volume', index)
switch (attribute) {
// extract RAID level
case 'level':
return /RAID Level (.*),/.exec(data.descr)[1]
// extract volume message
case 'message':
return /, (.*);/.exec(data.descr)[1]
// extract and parse used space to bytes
case 'used':
return bytes(/; ([^B]*)/.exec(data.descr)[1] + 'B')
// extract and parse volume size to bytes
case 'size':
return bytes(/of ([^B]*)/.exec(data.descr)[1] + 'B')
// calculate free space in bytes
case 'free':
return this.volumeInfo(index, 'size') - this.volumeInfo(index, 'used')
// just return entity attribute
default:
case 'status':
return data.status
}
}
/**
* count RAID volumes
*
* @return {Number}
*/
ReadyNAS.prototype.volumeCount = function () {
// return number of volume entities
return this.message.match(/volume!!\d+!!/g).length
}
/**
* DEPRECATED
*/
ReadyNAS.prototype.info = function () {
// print deprecation warning
deprecate('ReadyNAS#info() is deprecated')
// WTF ?
return this.getEntityAttribute('model', 'descr')
}
/**
* DEPRECATED
*/
ReadyNAS.prototype.status = function (entity, index) {
// print deprecation warning
deprecate('ReadyNAS#status() is deprecated, use ReadyNAS#getEntity() instead')
// alias of #getEntity()
return this.getEntity(entity, index)
}
/**
* @exports ReadyNAS
*/
module.exports = ReadyNAS