You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

234 lines
5.2 KiB

"use strict";
var fs = require("fs");
var path = require("path");
function buildNumberCheck(field) {
return function(typ, options, val) {
var value = parseInt(val, 10);
if(value !== val || value <= 0 || typ !== "number") throw new Error("'" + field + "' option must be a positive integer number");
};
}
function buildStringCheck(field, check) {
return function(typ, options, val) {
if(typ !== "string") throw new Error("Don't know how to handle 'options." + field + "' type: " + typ);
options[field] = check(val);
};
}
function checkMeasure(v, what, units) {
var ret = {};
ret.num = parseInt(v, 10);
if(isNaN(ret.num)) throw new Error("Unknown 'options." + what + "' format: " + v);
if(ret.num <= 0) throw new Error("A positive integer number is expected for 'options." + what + "'");
ret.unit = v.replace(/^[ 0]*/g, "").substr((ret.num + "").length, 1);
if(ret.unit.length === 0) throw new Error("Missing unit for 'options." + what + "'");
if(! units[ret.unit]) throw new Error("Unknown 'options." + what + "' unit: " + ret.unit);
return ret;
}
var intervalUnits = {
M: true,
d: true,
h: true,
m: true,
s: true
};
function checkIntervalUnit(ret, unit, amount) {
if(parseInt(amount / ret.num, 10) * ret.num !== amount) throw new Error("An integer divider of " + amount + " is expected as " + unit + " for 'options.interval'");
}
function checkInterval(v) {
var ret = checkMeasure(v, "interval", intervalUnits);
switch(ret.unit) {
case "h":
checkIntervalUnit(ret, "hours", 24);
break;
case "m":
checkIntervalUnit(ret, "minutes", 60);
break;
case "s":
checkIntervalUnit(ret, "seconds", 60);
break;
}
return ret;
}
var sizeUnits = {
B: true,
G: true,
K: true,
M: true
};
function checkSize(v) {
var ret = checkMeasure(v, "size", sizeUnits);
if(ret.unit === "K") return ret.num * 1024;
if(ret.unit === "M") return ret.num * 1048576;
if(ret.unit === "G") return ret.num * 1073741824;
return ret.num;
}
var checks = {
compress: function(typ, options, val) {
if(! val) throw new Error("A value for 'options.compress' must be specified");
if(typ === "boolean")
options.compress = function(src, dst) {
return "cat " + src + " | gzip -c9 > " + dst;
};
else if(typ === "string") {
//if(val != "bzip" && val != "gzip")
if(val !== "gzip") throw new Error("Don't know how to handle compression method: " + val);
}
else if(typ !== "function") throw new Error("Don't know how to handle 'options.compress' type: " + typ);
},
highWaterMark: function() {},
history: function(typ) {
if(typ !== "string") throw new Error("Don't know how to handle 'options.history' type: " + typ);
},
immutable: function() {},
initialRotation: function() {},
interval: buildStringCheck("interval", checkInterval),
maxFiles: buildNumberCheck("maxFiles"),
maxSize: buildStringCheck("maxSize", checkSize),
mode: function() {},
path: function(typ) {
if(typ !== "string") throw new Error("Don't know how to handle 'options.path' type: " + typ);
},
rotate: buildNumberCheck("rotate"),
rotationTime: function() {},
size: buildStringCheck("size", checkSize)
};
function checkOptions(options) {
if(! options) return {};
if(typeof options !== "object") throw new Error("Don't know how to handle 'options' type: " + typeof options);
var ret = {};
for(var opt in options) {
var val = options[opt];
var typ = typeof val;
if(! (opt in checks)) throw new Error("Unknown option: " + opt);
ret[opt] = options[opt];
checks[opt](typ, ret, val);
}
if(! ret.interval) {
delete ret.immutable;
delete ret.initialRotation;
delete ret.rotationTime;
}
if(ret.rotate) {
delete ret.history;
delete ret.immutable;
delete ret.maxFiles;
delete ret.maxSize;
delete ret.rotationTime;
}
if(ret.immutable) delete ret.compress;
if(ret.rotationTime) delete ret.initialRotation;
return ret;
}
function pad(num) {
return (num > 9 ? "" : "0") + num;
}
function createClassical(filename) {
return function(index) {
if(! index) return filename;
return filename + "." + index;
};
}
function createGenerator(filename) {
return function(time, index) {
if(! time) return filename;
var month = time.getFullYear() + "" + pad(time.getMonth() + 1);
var day = pad(time.getDate());
var hour = pad(time.getHours());
var minute = pad(time.getMinutes());
return month + day + "-" + hour + minute + "-" + pad(index) + "-" + filename;
};
}
function makePath(name, callback) {
var dir = path.parse(name).dir;
fs.mkdir(dir, function(e) {
if(e) {
if(e.code === "ENOENT") return makePath(dir, callback);
if(e.code !== "EEXIST") return callback(e);
}
callback();
});
}
function setEvents(self) {
self.once("error", function(err) {
self.err = err;
self.end();
});
self.once("finish", self._clear.bind(self));
self.on("rotated", function() {
self.rotation = null;
self._rewrite();
});
if((self.options.maxFiles || self.options.maxSize) && ! self.options.rotate) self.on(self.options.immutable ? "open" : "rotated", self.history.bind(self));
}
module.exports = {
checkOptions: checkOptions,
createClassical: createClassical,
createGenerator: createGenerator,
makePath: makePath,
setEvents: setEvents
};