mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-11-13 03:35:52 +01:00
153 lines
3.4 KiB
JavaScript
153 lines
3.4 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* file-locking.js - file system locking (replaces fs-ext)
|
|
*/
|
|
|
|
const async = require('async');
|
|
const locker = require('lockfile');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// locks a file by creating a lock file
|
|
const lockFile = function(name, next) {
|
|
const lockFileName = `${name}.lock`;
|
|
const lockOpts = {
|
|
wait: 1000, // time (ms) to wait when checking for stale locks
|
|
pollPeriod: 100, // how often (ms) to re-check stale locks
|
|
|
|
stale: 5 * 60 * 1000, // locks are considered stale after 5 minutes
|
|
|
|
retries: 100, // number of times to attempt to create a lock
|
|
retryWait: 100, // time (ms) between tries
|
|
};
|
|
|
|
async.series({
|
|
|
|
statdir: function(callback) {
|
|
// test to see if the directory exists
|
|
fs.stat(path.dirname(name), function(err, stats) {
|
|
if (err) {
|
|
callback(err);
|
|
} else if (!stats.isDirectory()) {
|
|
callback(new Error(path.dirname(name) + ' is not a directory'));
|
|
} else {
|
|
callback(null);
|
|
}
|
|
});
|
|
},
|
|
|
|
statfile: function(callback) {
|
|
// test to see if the file to lock exists
|
|
fs.stat(name, function(err, stats) {
|
|
if (err) {
|
|
callback(err);
|
|
} else if (!stats.isFile()) {
|
|
callback(new Error(path.dirname(name) + ' is not a file'));
|
|
} else {
|
|
callback(null);
|
|
}
|
|
});
|
|
},
|
|
|
|
lockfile: function(callback) {
|
|
// try to lock the file
|
|
locker.lock(lockFileName, lockOpts, callback);
|
|
},
|
|
|
|
}, function(err) {
|
|
if (err) {
|
|
// lock failed
|
|
return next(err);
|
|
}
|
|
|
|
// lock succeeded
|
|
return next(null);
|
|
});
|
|
};
|
|
|
|
// unlocks file by removing existing lock file
|
|
const unlockFile= function(name, next) {
|
|
const lockFileName = `${name}.lock`;
|
|
locker.unlock(lockFileName, function(err) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
return next(null);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Reads a local file, which involves
|
|
* optionally taking a lock
|
|
* reading the file contents
|
|
* optionally parsing JSON contents
|
|
* @param {*} name
|
|
* @param {*} options
|
|
* @param {*} next
|
|
*/
|
|
function readFile(name, options, next) {
|
|
if (typeof options === 'function' && next === null) {
|
|
next = options;
|
|
options = {};
|
|
}
|
|
|
|
options = options || {};
|
|
options.lock = options.lock || false;
|
|
options.parse = options.parse || false;
|
|
|
|
const lock = function(callback) {
|
|
if (!options.lock) {
|
|
return callback(null);
|
|
}
|
|
|
|
lockFile(name, function(err) {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
return callback(null);
|
|
});
|
|
};
|
|
|
|
const read = function(callback) {
|
|
fs.readFile(name, 'utf8', function(err, contents) {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
|
|
callback(null, contents);
|
|
});
|
|
};
|
|
|
|
const parseJSON = function(contents, callback) {
|
|
if (!options.parse) {
|
|
return callback(null, contents);
|
|
}
|
|
|
|
try {
|
|
contents = JSON.parse(contents);
|
|
return callback(null, contents);
|
|
} catch (err) {
|
|
return callback(err);
|
|
}
|
|
};
|
|
|
|
async.waterfall([
|
|
lock,
|
|
read,
|
|
parseJSON,
|
|
],
|
|
|
|
function(err, result) {
|
|
if (err) {
|
|
return next(err);
|
|
} else {
|
|
return next(null, result);
|
|
}
|
|
});
|
|
}
|
|
|
|
exports.lockFile = lockFile;
|
|
exports.unlockFile = unlockFile;
|
|
exports.readFile = readFile;
|