|
|
@ -13,9 +13,22 @@ const { callbackify, promisify } = require('util') |
|
|
|
const storage = {} |
|
|
|
const storage = {} |
|
|
|
const { Readable } = require('stream') |
|
|
|
const { Readable } = require('stream') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* @callback Storage~existsCallback |
|
|
|
|
|
|
|
* @param {boolean} exists |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* @param {string} file |
|
|
|
|
|
|
|
* @param {Storage~existsCallback} cb |
|
|
|
|
|
|
|
*/ |
|
|
|
// eslint-disable-next-line node/no-callback-literal
|
|
|
|
// eslint-disable-next-line node/no-callback-literal
|
|
|
|
storage.exists = (path, cb) => fs.access(path, fs.constants.F_OK, (err) => { cb(!err) }) |
|
|
|
storage.exists = (file, cb) => fs.access(file, fs.constants.F_OK, (err) => { cb(!err) }) |
|
|
|
storage.existsAsync = path => fsPromises.access(path, fs.constants.F_OK).then(() => true, () => false) |
|
|
|
/** |
|
|
|
|
|
|
|
* @param {string} file |
|
|
|
|
|
|
|
* @return {Promise<boolean>} |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
storage.existsAsync = file => fsPromises.access(file, fs.constants.F_OK).then(() => true, () => false) |
|
|
|
storage.rename = fs.rename |
|
|
|
storage.rename = fs.rename |
|
|
|
storage.renameAsync = fsPromises.rename |
|
|
|
storage.renameAsync = fsPromises.rename |
|
|
|
storage.writeFile = fs.writeFile |
|
|
|
storage.writeFile = fs.writeFile |
|
|
@ -32,22 +45,40 @@ storage.mkdir = fs.mkdir |
|
|
|
storage.mkdirAsync = fsPromises.mkdir |
|
|
|
storage.mkdirAsync = fsPromises.mkdir |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Explicit name ... |
|
|
|
* @param {string} file |
|
|
|
|
|
|
|
* @return {Promise<void>} |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
storage.ensureFileDoesntExistAsync = async file => { |
|
|
|
storage.ensureFileDoesntExistAsync = async file => { |
|
|
|
if (await storage.existsAsync(file)) await storage.unlinkAsync(file) |
|
|
|
if (await storage.existsAsync(file)) await storage.unlinkAsync(file) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* @callback Storage~errorCallback |
|
|
|
|
|
|
|
* @param {?Error} err |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* @param {string} file |
|
|
|
|
|
|
|
* @param {Storage~errorCallback} callback |
|
|
|
|
|
|
|
*/ |
|
|
|
storage.ensureFileDoesntExist = (file, callback) => callbackify(storage.ensureFileDoesntExistAsync)(file, err => callback(err)) |
|
|
|
storage.ensureFileDoesntExist = (file, callback) => callbackify(storage.ensureFileDoesntExistAsync)(file, err => callback(err)) |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Flush data in OS buffer to storage if corresponding option is set |
|
|
|
* Flush data in OS buffer to storage if corresponding option is set |
|
|
|
* @param {String} options.filename |
|
|
|
* @param {object|string} options If options is a string, it is assumed that the flush of the file (not dir) called options was requested |
|
|
|
* @param {Boolean} options.isDir Optional, defaults to false |
|
|
|
* @param {string} [options.filename] |
|
|
|
* If options is a string, it is assumed that the flush of the file (not dir) called options was requested |
|
|
|
* @param {boolean} [options.isDir = false] Optional, defaults to false |
|
|
|
|
|
|
|
* @param {Storage~errorCallback} callback |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
storage.flushToStorage = (options, callback) => callbackify(storage.flushToStorageAsync)(options, callback) |
|
|
|
storage.flushToStorage = (options, callback) => callbackify(storage.flushToStorageAsync)(options, callback) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Flush data in OS buffer to storage if corresponding option is set |
|
|
|
|
|
|
|
* @param {object|string} options If options is a string, it is assumed that the flush of the file (not dir) called options was requested |
|
|
|
|
|
|
|
* @param {string} [options.filename] |
|
|
|
|
|
|
|
* @param {boolean} [options.isDir = false] Optional, defaults to false |
|
|
|
|
|
|
|
* @return {Promise<void>} |
|
|
|
|
|
|
|
*/ |
|
|
|
storage.flushToStorageAsync = async (options) => { |
|
|
|
storage.flushToStorageAsync = async (options) => { |
|
|
|
let filename |
|
|
|
let filename |
|
|
|
let flags |
|
|
|
let flags |
|
|
@ -98,9 +129,9 @@ storage.flushToStorageAsync = async (options) => { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Fully write or rewrite the datafile |
|
|
|
* Fully write or rewrite the datafile |
|
|
|
* @param {String} filename |
|
|
|
* @param {string} filename |
|
|
|
* @param {String[]} lines |
|
|
|
* @param {string[]} lines |
|
|
|
* @param {Function} callback |
|
|
|
* @param {Storage~errorCallback} callback |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
storage.writeFileLines = (filename, lines, callback = () => {}) => { |
|
|
|
storage.writeFileLines = (filename, lines, callback = () => {}) => { |
|
|
|
try { |
|
|
|
try { |
|
|
@ -122,19 +153,30 @@ storage.writeFileLines = (filename, lines, callback = () => {}) => { |
|
|
|
callback(err) |
|
|
|
callback(err) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Fully write or rewrite the datafile |
|
|
|
|
|
|
|
* @param {string} filename |
|
|
|
|
|
|
|
* @param {string[]} lines |
|
|
|
|
|
|
|
* @return {Promise<void>} |
|
|
|
|
|
|
|
* @async |
|
|
|
|
|
|
|
*/ |
|
|
|
storage.writeFileLinesAsync = (filename, lines) => promisify(storage.writeFileLines)(filename, lines) |
|
|
|
storage.writeFileLinesAsync = (filename, lines) => promisify(storage.writeFileLines)(filename, lines) |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Fully write or rewrite the datafile, immune to crashes during the write operation (data will not be lost) |
|
|
|
* Fully write or rewrite the datafile, immune to crashes during the write operation (data will not be lost) |
|
|
|
* @param {String} filename |
|
|
|
* @param {string} filename |
|
|
|
* @param {String[]} lines |
|
|
|
* @param {string[]} lines |
|
|
|
* @param {Function} callback Optional callback, signature: err |
|
|
|
* @param {Storage~errorCallback} callback Optional callback, signature: err |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
storage.crashSafeWriteFileLines = (filename, lines, callback = () => {}) => { |
|
|
|
storage.crashSafeWriteFileLines = (filename, lines, callback = () => {}) => { |
|
|
|
callbackify(storage.crashSafeWriteFileLinesAsync)(filename, lines, callback) |
|
|
|
callbackify(storage.crashSafeWriteFileLinesAsync)(filename, lines, callback) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Fully write or rewrite the datafile, immune to crashes during the write operation (data will not be lost) |
|
|
|
|
|
|
|
* @param {string} filename |
|
|
|
|
|
|
|
* @param {string[]} lines |
|
|
|
|
|
|
|
* @return {Promise<void>} |
|
|
|
|
|
|
|
*/ |
|
|
|
storage.crashSafeWriteFileLinesAsync = async (filename, lines) => { |
|
|
|
storage.crashSafeWriteFileLinesAsync = async (filename, lines) => { |
|
|
|
const tempFilename = filename + '~' |
|
|
|
const tempFilename = filename + '~' |
|
|
|
|
|
|
|
|
|
|
@ -154,11 +196,16 @@ storage.crashSafeWriteFileLinesAsync = async (filename, lines) => { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Ensure the datafile contains all the data, even if there was a crash during a full file write |
|
|
|
* Ensure the datafile contains all the data, even if there was a crash during a full file write |
|
|
|
* @param {String} filename |
|
|
|
* @param {string} filename |
|
|
|
* @param {Function} callback signature: err |
|
|
|
* @param {Storage~errorCallback} callback signature: err |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
storage.ensureDatafileIntegrity = (filename, callback) => callbackify(storage.ensureDatafileIntegrityAsync)(filename, callback) |
|
|
|
storage.ensureDatafileIntegrity = (filename, callback) => callbackify(storage.ensureDatafileIntegrityAsync)(filename, callback) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Ensure the datafile contains all the data, even if there was a crash during a full file write |
|
|
|
|
|
|
|
* @param {string} filename |
|
|
|
|
|
|
|
* @return {Promise<void>} |
|
|
|
|
|
|
|
*/ |
|
|
|
storage.ensureDatafileIntegrityAsync = async filename => { |
|
|
|
storage.ensureDatafileIntegrityAsync = async filename => { |
|
|
|
const tempFilename = filename + '~' |
|
|
|
const tempFilename = filename + '~' |
|
|
|
|
|
|
|
|
|
|
|