logo

mastofe

My custom branche(s) on git.pleroma.social/pleroma/mastofe git clone https://hacktivis.me/git/mastofe.git

modifier.js (5835B)


  1. import openDB from './db';
  2. const accountAssetKeys = ['avatar', 'avatar_static', 'header', 'header_static'];
  3. const storageMargin = 8388608;
  4. const storeLimit = 1024;
  5. function openCache() {
  6. // ServiceWorker and Cache API is not available on iOS 11
  7. // https://webkit.org/status/#specification-service-workers
  8. return self.caches ? caches.open('mastodon-system') : Promise.reject();
  9. }
  10. function printErrorIfAvailable(error) {
  11. if (error) {
  12. console.warn(error);
  13. }
  14. }
  15. function put(name, objects, onupdate, oncreate) {
  16. return openDB().then(db => (new Promise((resolve, reject) => {
  17. const putTransaction = db.transaction(name, 'readwrite');
  18. const putStore = putTransaction.objectStore(name);
  19. const putIndex = putStore.index('id');
  20. objects.forEach(object => {
  21. putIndex.getKey(object.id).onsuccess = retrieval => {
  22. function addObject() {
  23. putStore.add(object);
  24. }
  25. function deleteObject() {
  26. putStore.delete(retrieval.target.result).onsuccess = addObject;
  27. }
  28. if (retrieval.target.result) {
  29. if (onupdate) {
  30. onupdate(object, retrieval.target.result, putStore, deleteObject);
  31. } else {
  32. deleteObject();
  33. }
  34. } else {
  35. if (oncreate) {
  36. oncreate(object, addObject);
  37. } else {
  38. addObject();
  39. }
  40. }
  41. };
  42. });
  43. putTransaction.oncomplete = () => {
  44. const readTransaction = db.transaction(name, 'readonly');
  45. const readStore = readTransaction.objectStore(name);
  46. const count = readStore.count();
  47. count.onsuccess = () => {
  48. const excess = count.result - storeLimit;
  49. if (excess > 0) {
  50. const retrieval = readStore.getAll(null, excess);
  51. retrieval.onsuccess = () => resolve(retrieval.result);
  52. retrieval.onerror = reject;
  53. } else {
  54. resolve([]);
  55. }
  56. };
  57. count.onerror = reject;
  58. };
  59. putTransaction.onerror = reject;
  60. })).then(resolved => {
  61. db.close();
  62. return resolved;
  63. }, error => {
  64. db.close();
  65. throw error;
  66. }));
  67. }
  68. function evictAccountsByRecords(records) {
  69. return openDB().then(db => {
  70. const transaction = db.transaction(['accounts', 'statuses'], 'readwrite');
  71. const accounts = transaction.objectStore('accounts');
  72. const accountsIdIndex = accounts.index('id');
  73. const accountsMovedIndex = accounts.index('moved');
  74. const statuses = transaction.objectStore('statuses');
  75. const statusesIndex = statuses.index('account');
  76. function evict(toEvict) {
  77. toEvict.forEach(record => {
  78. openCache()
  79. .then(cache => accountAssetKeys.forEach(key => cache.delete(records[key])))
  80. .catch(printErrorIfAvailable);
  81. accountsMovedIndex.getAll(record.id).onsuccess = ({ target }) => evict(target.result);
  82. statusesIndex.getAll(record.id).onsuccess =
  83. ({ target }) => evictStatusesByRecords(target.result);
  84. accountsIdIndex.getKey(record.id).onsuccess =
  85. ({ target }) => target.result && accounts.delete(target.result);
  86. });
  87. }
  88. evict(records);
  89. db.close();
  90. }).catch(printErrorIfAvailable);
  91. }
  92. export function evictStatus(id) {
  93. evictStatuses([id]);
  94. }
  95. export function evictStatuses(ids) {
  96. return openDB().then(db => {
  97. const transaction = db.transaction('statuses', 'readwrite');
  98. const store = transaction.objectStore('statuses');
  99. const idIndex = store.index('id');
  100. const reblogIndex = store.index('reblog');
  101. ids.forEach(id => {
  102. reblogIndex.getAllKeys(id).onsuccess =
  103. ({ target }) => target.result.forEach(reblogKey => store.delete(reblogKey));
  104. idIndex.getKey(id).onsuccess =
  105. ({ target }) => target.result && store.delete(target.result);
  106. });
  107. db.close();
  108. }).catch(printErrorIfAvailable);
  109. }
  110. function evictStatusesByRecords(records) {
  111. return evictStatuses(records.map(({ id }) => id));
  112. }
  113. export function putAccounts(records, avatarStatic) {
  114. const avatarKey = avatarStatic ? 'avatar_static' : 'avatar';
  115. const newURLs = [];
  116. put('accounts', records, (newRecord, oldKey, store, oncomplete) => {
  117. store.get(oldKey).onsuccess = ({ target }) => {
  118. accountAssetKeys.forEach(key => {
  119. const newURL = newRecord[key];
  120. const oldURL = target.result[key];
  121. if (newURL !== oldURL) {
  122. openCache()
  123. .then(cache => cache.delete(oldURL))
  124. .catch(printErrorIfAvailable);
  125. }
  126. });
  127. const newURL = newRecord[avatarKey];
  128. const oldURL = target.result[avatarKey];
  129. if (newURL !== oldURL) {
  130. newURLs.push(newURL);
  131. }
  132. oncomplete();
  133. };
  134. }, (newRecord, oncomplete) => {
  135. newURLs.push(newRecord[avatarKey]);
  136. oncomplete();
  137. }).then(records => Promise.all([
  138. evictAccountsByRecords(records),
  139. openCache().then(cache => cache.addAll(newURLs)),
  140. ])).then(freeStorage, error => {
  141. freeStorage();
  142. throw error;
  143. }).catch(printErrorIfAvailable);
  144. }
  145. export function putStatuses(records) {
  146. put('statuses', records)
  147. .then(evictStatusesByRecords)
  148. .catch(printErrorIfAvailable);
  149. }
  150. export function freeStorage() {
  151. return navigator.storage.estimate().then(({ quota, usage }) => {
  152. if (usage + storageMargin < quota) {
  153. return null;
  154. }
  155. return openDB().then(db => new Promise((resolve, reject) => {
  156. const retrieval = db.transaction('accounts', 'readonly').objectStore('accounts').getAll(null, 1);
  157. retrieval.onsuccess = () => {
  158. if (retrieval.result.length > 0) {
  159. resolve(evictAccountsByRecords(retrieval.result).then(freeStorage));
  160. } else {
  161. resolve(caches.delete('mastodon-system'));
  162. }
  163. };
  164. retrieval.onerror = reject;
  165. db.close();
  166. }));
  167. });
  168. }