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
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;
|
|
|