mirror of https://github.com/miraclx/freyr-js
80 lines
2.2 KiB
JavaScript
80 lines
2.2 KiB
JavaScript
import {join, resolve, dirname} from 'path';
|
|
import {tmpdir} from 'os';
|
|
import {createHash} from 'crypto';
|
|
import {promises as fs, constants as fs_constants} from 'fs';
|
|
|
|
import mkdirp from 'mkdirp';
|
|
import esMain from 'es-main';
|
|
|
|
const openfiles = {};
|
|
const removeCallbacks = [];
|
|
|
|
function garbageCollector() {
|
|
while (removeCallbacks.length) removeCallbacks.pop()();
|
|
process.removeListener('exit', garbageCollector);
|
|
}
|
|
|
|
let hookedUpListeners = false;
|
|
function hookupListeners() {
|
|
if (!hookedUpListeners) {
|
|
hookedUpListeners = true;
|
|
process.addListener('exit', garbageCollector);
|
|
}
|
|
}
|
|
|
|
export default async function genFile(opts) {
|
|
opts = opts || {};
|
|
let mode = fs_constants.O_CREAT | opts.mode;
|
|
const path = resolve(join('tmpdir' in opts ? opts['tmpdir'] : tmpdir(), opts.dirname || '.', opts.filename));
|
|
let id = createHash('md5').update(`Ξ${mode}${path}`).digest('hex');
|
|
let file = openfiles[id];
|
|
if (!file) {
|
|
await mkdirp(dirname(path));
|
|
file = openfiles[id] = {
|
|
path,
|
|
handle: await fs.open(path, mode),
|
|
refs: 1,
|
|
closed: false,
|
|
keep: false,
|
|
};
|
|
} else file.refs += 1;
|
|
hookupListeners();
|
|
const garbageHandler = async keep => {
|
|
file.keep ||= keep !== undefined ? keep : opts.keep;
|
|
if ((file.refs = Math.max(0, file.refs - 1))) return;
|
|
if (file.closed) return;
|
|
file.closed = true;
|
|
delete openfiles[id];
|
|
await file.handle.close();
|
|
if (!file.keep) await fs.unlink(path);
|
|
};
|
|
removeCallbacks.push(garbageHandler);
|
|
return {
|
|
path,
|
|
handle: file.handle,
|
|
removeCallback: async () => {
|
|
await garbageHandler(false);
|
|
removeCallbacks.splice(removeCallbacks.indexOf(garbageHandler), 1);
|
|
},
|
|
};
|
|
}
|
|
|
|
async function test() {
|
|
const filename = 'freyr_mgr_temp_file';
|
|
async function testMgr(args) {
|
|
const file = await genFile({filename, ...args});
|
|
console.log('mgr>', file);
|
|
return file;
|
|
}
|
|
let a = await testMgr();
|
|
let b = await testMgr();
|
|
await testMgr({keep: true});
|
|
let d = await testMgr();
|
|
a.removeCallback();
|
|
b.removeCallback();
|
|
// c.removeCallback(); // calling this would negate the keep directive
|
|
d.removeCallback();
|
|
}
|
|
|
|
if (esMain(import.meta)) test().catch(err => console.error('cli>', err));
|