storage.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import { arrayToB64, isFile } from './utils';
  2. import OwnedFile from './ownedFile';
  3. class Mem {
  4. constructor() {
  5. this.items = new Map();
  6. }
  7. get length() {
  8. return this.items.size;
  9. }
  10. getItem(key) {
  11. return this.items.get(key);
  12. }
  13. setItem(key, value) {
  14. return this.items.set(key, value);
  15. }
  16. removeItem(key) {
  17. return this.items.delete(key);
  18. }
  19. key(i) {
  20. return this.items.keys()[i];
  21. }
  22. }
  23. class Storage {
  24. constructor() {
  25. try {
  26. this.engine = localStorage || new Mem();
  27. } catch (e) {
  28. this.engine = new Mem();
  29. }
  30. this._files = this.loadFiles();
  31. }
  32. loadFiles() {
  33. const fs = new Map();
  34. for (let i = 0; i < this.engine.length; i++) {
  35. const k = this.engine.key(i);
  36. if (isFile(k)) {
  37. try {
  38. const f = new OwnedFile(JSON.parse(this.engine.getItem(k)));
  39. if (!f.id) {
  40. f.id = f.fileId;
  41. }
  42. fs.set(f.id, f);
  43. } catch (err) {
  44. // obviously you're not a golfer
  45. this.engine.removeItem(k);
  46. }
  47. }
  48. }
  49. return fs;
  50. }
  51. get id() {
  52. let id = this.engine.getItem('device_id');
  53. if (!id) {
  54. id = arrayToB64(crypto.getRandomValues(new Uint8Array(16)));
  55. this.engine.setItem('device_id', id);
  56. }
  57. return id;
  58. }
  59. get totalDownloads() {
  60. return Number(this.engine.getItem('totalDownloads'));
  61. }
  62. set totalDownloads(n) {
  63. this.engine.setItem('totalDownloads', n);
  64. }
  65. get totalUploads() {
  66. return Number(this.engine.getItem('totalUploads'));
  67. }
  68. set totalUploads(n) {
  69. this.engine.setItem('totalUploads', n);
  70. }
  71. get referrer() {
  72. return this.engine.getItem('referrer');
  73. }
  74. set referrer(str) {
  75. this.engine.setItem('referrer', str);
  76. }
  77. get enrolled() {
  78. return JSON.parse(this.engine.getItem('ab_experiments') || '{}');
  79. }
  80. enroll(id, variant) {
  81. const enrolled = {};
  82. enrolled[id] = variant;
  83. this.engine.setItem('ab_experiments', JSON.stringify(enrolled));
  84. }
  85. get files() {
  86. return Array.from(this._files.values()).sort(
  87. (a, b) => a.createdAt - b.createdAt
  88. );
  89. }
  90. get user() {
  91. try {
  92. return JSON.parse(this.engine.getItem('user'));
  93. } catch (e) {
  94. return null;
  95. }
  96. }
  97. set user(info) {
  98. return this.engine.setItem('user', JSON.stringify(info));
  99. }
  100. getFileById(id) {
  101. return this._files.get(id);
  102. }
  103. get(id) {
  104. return this.engine.getItem(id);
  105. }
  106. set(id, value) {
  107. return this.engine.setItem(id, value);
  108. }
  109. remove(property) {
  110. if (isFile(property)) {
  111. this._files.delete(property);
  112. }
  113. this.engine.removeItem(property);
  114. }
  115. addFile(file) {
  116. this._files.set(file.id, file);
  117. this.writeFile(file);
  118. }
  119. writeFile(file) {
  120. this.engine.setItem(file.id, JSON.stringify(file));
  121. }
  122. writeFiles() {
  123. this._files.forEach(f => this.writeFile(f));
  124. }
  125. clearLocalFiles() {
  126. this._files.forEach(f => this.engine.removeItem(f.id));
  127. this._files = new Map();
  128. }
  129. async merge(files = []) {
  130. let incoming = false;
  131. let outgoing = false;
  132. let downloadCount = false;
  133. for (const f of files) {
  134. if (!this.getFileById(f.id)) {
  135. this.addFile(new OwnedFile(f));
  136. incoming = true;
  137. }
  138. }
  139. const workingFiles = this.files.slice();
  140. for (const f of workingFiles) {
  141. const cc = await f.updateDownloadCount();
  142. if (cc) {
  143. await this.writeFile(f);
  144. }
  145. downloadCount = downloadCount || cc;
  146. outgoing = outgoing || f.expired;
  147. if (f.expired) {
  148. this.remove(f.id);
  149. } else if (!files.find(x => x.id === f.id)) {
  150. outgoing = true;
  151. }
  152. }
  153. return {
  154. incoming,
  155. outgoing,
  156. downloadCount
  157. };
  158. }
  159. }
  160. export default new Storage();