This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
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.
283 lines
6.4 KiB
283 lines
6.4 KiB
var fs = require('fs'), |
|
path = require('path'), |
|
cnst = require('constants'); |
|
|
|
var rimraf = require('rimraf'), |
|
osTmpdir = require('os-tmpdir'), |
|
rimrafSync = rimraf.sync; |
|
|
|
/* HELPERS */ |
|
|
|
var RDWR_EXCL = cnst.O_CREAT | cnst.O_TRUNC | cnst.O_RDWR | cnst.O_EXCL; |
|
|
|
var generateName = function(rawAffixes, defaultPrefix) { |
|
var affixes = parseAffixes(rawAffixes, defaultPrefix); |
|
var now = new Date(); |
|
var name = [affixes.prefix, |
|
now.getYear(), now.getMonth(), now.getDate(), |
|
'-', |
|
process.pid, |
|
'-', |
|
(Math.random() * 0x100000000 + 1).toString(36), |
|
affixes.suffix].join(''); |
|
return path.join(affixes.dir || exports.dir, name); |
|
}; |
|
|
|
var parseAffixes = function(rawAffixes, defaultPrefix) { |
|
var affixes = {prefix: null, suffix: null}; |
|
if(rawAffixes) { |
|
switch (typeof(rawAffixes)) { |
|
case 'string': |
|
affixes.prefix = rawAffixes; |
|
break; |
|
case 'object': |
|
affixes = rawAffixes; |
|
break; |
|
default: |
|
throw new Error("Unknown affix declaration: " + affixes); |
|
} |
|
} else { |
|
affixes.prefix = defaultPrefix; |
|
} |
|
return affixes; |
|
}; |
|
|
|
/* ------------------------------------------------------------------------- |
|
* Don't forget to call track() if you want file tracking and exit handlers! |
|
* ------------------------------------------------------------------------- |
|
* When any temp file or directory is created, it is added to filesToDelete |
|
* or dirsToDelete. The first time any temp file is created, a listener is |
|
* added to remove all temp files and directories at exit. |
|
*/ |
|
var tracking = false; |
|
var track = function(value) { |
|
tracking = (value !== false); |
|
return module.exports; // chainable |
|
}; |
|
var exitListenerAttached = false; |
|
var filesToDelete = []; |
|
var dirsToDelete = []; |
|
|
|
function deleteFileOnExit(filePath) { |
|
if (!tracking) return false; |
|
attachExitListener(); |
|
filesToDelete.push(filePath); |
|
} |
|
|
|
function deleteDirOnExit(dirPath) { |
|
if (!tracking) return false; |
|
attachExitListener(); |
|
dirsToDelete.push(dirPath); |
|
} |
|
|
|
function attachExitListener() { |
|
if (!tracking) return false; |
|
if (!exitListenerAttached) { |
|
process.addListener('exit', cleanupSync); |
|
exitListenerAttached = true; |
|
} |
|
} |
|
|
|
function cleanupFilesSync() { |
|
if (!tracking) { |
|
return false; |
|
} |
|
var count = 0; |
|
var toDelete; |
|
while ((toDelete = filesToDelete.shift()) !== undefined) { |
|
rimrafSync(toDelete); |
|
count++; |
|
} |
|
return count; |
|
} |
|
|
|
function cleanupFiles(callback) { |
|
if (!tracking) { |
|
if (callback) { |
|
callback(new Error("not tracking")); |
|
} |
|
return; |
|
} |
|
var count = 0; |
|
var left = filesToDelete.length; |
|
if (!left) { |
|
if (callback) { |
|
callback(null, count); |
|
} |
|
return; |
|
} |
|
var toDelete; |
|
var rimrafCallback = function(err) { |
|
if (!left) { |
|
// Prevent processing if aborted |
|
return; |
|
} |
|
if (err) { |
|
// This shouldn't happen; pass error to callback and abort |
|
// processing |
|
if (callback) { |
|
callback(err); |
|
} |
|
left = 0; |
|
return; |
|
} else { |
|
count++; |
|
} |
|
left--; |
|
if (!left && callback) { |
|
callback(null, count); |
|
} |
|
}; |
|
while ((toDelete = filesToDelete.shift()) !== undefined) { |
|
rimraf(toDelete, rimrafCallback); |
|
} |
|
} |
|
|
|
function cleanupDirsSync() { |
|
if (!tracking) { |
|
return false; |
|
} |
|
var count = 0; |
|
var toDelete; |
|
while ((toDelete = dirsToDelete.shift()) !== undefined) { |
|
rimrafSync(toDelete); |
|
count++; |
|
} |
|
return count; |
|
} |
|
|
|
function cleanupDirs(callback) { |
|
if (!tracking) { |
|
if (callback) { |
|
callback(new Error("not tracking")); |
|
} |
|
return; |
|
} |
|
var count = 0; |
|
var left = dirsToDelete.length; |
|
if (!left) { |
|
if (callback) { |
|
callback(null, count); |
|
} |
|
return; |
|
} |
|
var toDelete; |
|
var rimrafCallback = function (err) { |
|
if (!left) { |
|
// Prevent processing if aborted |
|
return; |
|
} |
|
if (err) { |
|
// rimraf handles most "normal" errors; pass the error to the |
|
// callback and abort processing |
|
if (callback) { |
|
callback(err, count); |
|
} |
|
left = 0; |
|
return; |
|
} else { |
|
count; |
|
} |
|
left--; |
|
if (!left && callback) { |
|
callback(null, count); |
|
} |
|
}; |
|
while ((toDelete = dirsToDelete.shift()) !== undefined) { |
|
rimraf(toDelete, rimrafCallback); |
|
} |
|
} |
|
|
|
function cleanupSync() { |
|
if (!tracking) { |
|
return false; |
|
} |
|
var fileCount = cleanupFilesSync(); |
|
var dirCount = cleanupDirsSync(); |
|
return {files: fileCount, dirs: dirCount}; |
|
} |
|
|
|
function cleanup(callback) { |
|
if (!tracking) { |
|
if (callback) { |
|
callback(new Error("not tracking")); |
|
} |
|
return; |
|
} |
|
cleanupFiles(function(fileErr, fileCount) { |
|
if (fileErr) { |
|
if (callback) { |
|
callback(fileErr, {files: fileCount}) |
|
} |
|
} else { |
|
cleanupDirs(function(dirErr, dirCount) { |
|
if (callback) { |
|
callback(dirErr, {files: fileCount, dirs: dirCount}); |
|
} |
|
}); |
|
} |
|
}); |
|
} |
|
|
|
/* DIRECTORIES */ |
|
|
|
function mkdir(affixes, callback) { |
|
var dirPath = generateName(affixes, 'd-'); |
|
fs.mkdir(dirPath, 0700, function(err) { |
|
if (!err) { |
|
deleteDirOnExit(dirPath); |
|
} |
|
if (callback) { |
|
callback(err, dirPath); |
|
} |
|
}); |
|
} |
|
|
|
function mkdirSync(affixes) { |
|
var dirPath = generateName(affixes, 'd-'); |
|
fs.mkdirSync(dirPath, 0700); |
|
deleteDirOnExit(dirPath); |
|
return dirPath; |
|
} |
|
|
|
/* FILES */ |
|
|
|
function open(affixes, callback) { |
|
var filePath = generateName(affixes, 'f-'); |
|
fs.open(filePath, RDWR_EXCL, 0600, function(err, fd) { |
|
if (!err) { |
|
deleteFileOnExit(filePath); |
|
} |
|
if (callback) { |
|
callback(err, {path: filePath, fd: fd}); |
|
} |
|
}); |
|
} |
|
|
|
function openSync(affixes) { |
|
var filePath = generateName(affixes, 'f-'); |
|
var fd = fs.openSync(filePath, RDWR_EXCL, 0600); |
|
deleteFileOnExit(filePath); |
|
return {path: filePath, fd: fd}; |
|
} |
|
|
|
function createWriteStream(affixes) { |
|
var filePath = generateName(affixes, 's-'); |
|
var stream = fs.createWriteStream(filePath, {flags: RDWR_EXCL, mode: 0600}); |
|
deleteFileOnExit(filePath); |
|
return stream; |
|
} |
|
|
|
/* EXPORTS */ |
|
// Settings |
|
exports.dir = path.resolve(osTmpdir()); |
|
exports.track = track; |
|
// Functions |
|
exports.mkdir = mkdir; |
|
exports.mkdirSync = mkdirSync; |
|
exports.open = open; |
|
exports.openSync = openSync; |
|
exports.path = generateName; |
|
exports.cleanup = cleanup; |
|
exports.cleanupSync = cleanupSync; |
|
exports.createWriteStream = createWriteStream;
|
|
|