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.
 
 
 
 
 

138 lines
3.5 KiB

const isStr = require('./isStr');
const isObj = require('./isObj');
const each = require('./each');
const Emitter = require('./Emitter');
const toArr = require('./toArr');
const unique = require('./unique');
const concat = require('./concat');
const keys = require('./keys');
const fs = require('fs');
exports = Emitter.extend({
initialize: function FileBlobStore(path, data) {
this.callSuper(Emitter, 'initialize', arguments);
this._path = path;
this._mapPath = path + '.MAP';
this._lockPath = path + '.LOCK';
this._data = data || {};
let storedBlob = Buffer.alloc(0);
let storedBlobMap = {};
if (fs.existsSync(path) && fs.existsSync(this._mapPath)) {
try {
storedBlob = fs.readFileSync(path);
storedBlobMap = JSON.parse(fs.readFileSync(this._mapPath));
} catch (e) {
storedBlobMap = {};
storedBlob = Buffer.alloc(0);
}
}
this._storedBlob = storedBlob;
this._storedBlobMap = storedBlobMap;
},
set(key, buf) {
let data;
if (isStr(key)) {
data = {};
data[key] = buf;
} else if (isObj(key)) {
data = key;
}
each(data, (buf, key) => {
const oldBuf = this.get(key);
this._data[key] = buf;
this.emit('change', key, buf, oldBuf);
});
},
get(key) {
if (isStr(key)) {
return this._get(key);
}
const ret = {};
each(key, val => {
ret[val] = this._get(val);
});
return ret;
},
remove(key) {
key = toArr(key);
const data = this._data;
const storedBlobMap = this._storedBlobMap;
each(key, val => {
delete data[val];
delete storedBlobMap[val];
});
},
clear() {
this._data = {};
this._storedBlob = Buffer.alloc(0);
this._storedBlobMap = {};
},
each(fn) {
const allKeys = this._getKeys();
each(allKeys, key => {
fn(this._get(key), key);
});
},
save() {
const dump = this._getDump();
const blobToStore = Buffer.concat(dump[0]);
const mapToStore = JSON.stringify(dump[1]);
let lock = false;
try {
fs.writeFileSync(this._lockPath, 'LOCK', { flag: 'wx' });
lock = true;
fs.writeFileSync(this._path, blobToStore);
fs.writeFileSync(this._mapPath, mapToStore);
} catch (error) {
if (error.code !== 'EEXIST') {
throw error;
}
} finally {
if (lock) {
fs.unlinkSync(this._lockPath);
}
}
},
_get(key) {
return this._data[key] || this._getFromStorage(key);
},
_getFromStorage(key) {
if (!this._storedBlobMap[key]) {
return;
}
const [start, end] = this._storedBlobMap[key];
return this._storedBlob.slice(start, end);
},
_getDump() {
const buffers = [];
const blobMap = {};
let curBufStart = 0;
function dump(buf, key) {
buffers.push(buf);
const len = buf.length;
blobMap[key] = [curBufStart, curBufStart + len];
curBufStart += len;
}
this.each(dump);
return [buffers, blobMap];
},
_getKeys() {
return unique(concat(keys(this._data), keys(this._storedBlobMap)));
}
});
module.exports = exports;