FileBlobStore.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. const isStr = require('./isStr');
  2. const isObj = require('./isObj');
  3. const each = require('./each');
  4. const Emitter = require('./Emitter');
  5. const toArr = require('./toArr');
  6. const unique = require('./unique');
  7. const concat = require('./concat');
  8. const keys = require('./keys');
  9. const fs = require('fs');
  10. exports = Emitter.extend({
  11. initialize: function FileBlobStore(path, data) {
  12. this.callSuper(Emitter, 'initialize', arguments);
  13. this._path = path;
  14. this._mapPath = path + '.MAP';
  15. this._lockPath = path + '.LOCK';
  16. this._data = data || {};
  17. let storedBlob = Buffer.alloc(0);
  18. let storedBlobMap = {};
  19. if (fs.existsSync(path) && fs.existsSync(this._mapPath)) {
  20. try {
  21. storedBlob = fs.readFileSync(path);
  22. storedBlobMap = JSON.parse(fs.readFileSync(this._mapPath));
  23. } catch (e) {
  24. storedBlobMap = {};
  25. storedBlob = Buffer.alloc(0);
  26. }
  27. }
  28. this._storedBlob = storedBlob;
  29. this._storedBlobMap = storedBlobMap;
  30. },
  31. set(key, buf) {
  32. let data;
  33. if (isStr(key)) {
  34. data = {};
  35. data[key] = buf;
  36. } else if (isObj(key)) {
  37. data = key;
  38. }
  39. each(data, (buf, key) => {
  40. const oldBuf = this.get(key);
  41. this._data[key] = buf;
  42. this.emit('change', key, buf, oldBuf);
  43. });
  44. },
  45. get(key) {
  46. if (isStr(key)) {
  47. return this._get(key);
  48. }
  49. const ret = {};
  50. each(key, val => {
  51. ret[val] = this._get(val);
  52. });
  53. return ret;
  54. },
  55. remove(key) {
  56. key = toArr(key);
  57. const data = this._data;
  58. const storedBlobMap = this._storedBlobMap;
  59. each(key, val => {
  60. delete data[val];
  61. delete storedBlobMap[val];
  62. });
  63. },
  64. clear() {
  65. this._data = {};
  66. this._storedBlob = Buffer.alloc(0);
  67. this._storedBlobMap = {};
  68. },
  69. each(fn) {
  70. const allKeys = this._getKeys();
  71. each(allKeys, key => {
  72. fn(this._get(key), key);
  73. });
  74. },
  75. save() {
  76. const dump = this._getDump();
  77. const blobToStore = Buffer.concat(dump[0]);
  78. const mapToStore = JSON.stringify(dump[1]);
  79. let lock = false;
  80. try {
  81. fs.writeFileSync(this._lockPath, 'LOCK', { flag: 'wx' });
  82. lock = true;
  83. fs.writeFileSync(this._path, blobToStore);
  84. fs.writeFileSync(this._mapPath, mapToStore);
  85. } catch (error) {
  86. if (error.code !== 'EEXIST') {
  87. throw error;
  88. }
  89. } finally {
  90. if (lock) {
  91. fs.unlinkSync(this._lockPath);
  92. }
  93. }
  94. },
  95. _get(key) {
  96. return this._data[key] || this._getFromStorage(key);
  97. },
  98. _getFromStorage(key) {
  99. if (!this._storedBlobMap[key]) {
  100. return;
  101. }
  102. const [start, end] = this._storedBlobMap[key];
  103. return this._storedBlob.slice(start, end);
  104. },
  105. _getDump() {
  106. const buffers = [];
  107. const blobMap = {};
  108. let curBufStart = 0;
  109. function dump(buf, key) {
  110. buffers.push(buf);
  111. const len = buf.length;
  112. blobMap[key] = [curBufStart, curBufStart + len];
  113. curBufStart += len;
  114. }
  115. this.each(dump);
  116. return [buffers, blobMap];
  117. },
  118. _getKeys() {
  119. return unique(concat(keys(this._data), keys(this._storedBlobMap)));
  120. }
  121. });
  122. module.exports = exports;