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.

151 lines
4.3 KiB

  1. import asyncDB from './db';
  2. import { autoPlayGif } from '../initial_state';
  3. const accountAssetKeys = ['avatar', 'avatar_static', 'header', 'header_static'];
  4. const avatarKey = autoPlayGif ? 'avatar' : 'avatar_static';
  5. const limit = 1024;
  6. const asyncCache = caches.open('mastodon-system');
  7. function put(name, objects, onupdate, oncreate) {
  8. return asyncDB.then(db => new Promise((resolve, reject) => {
  9. const putTransaction = db.transaction(name, 'readwrite');
  10. const putStore = putTransaction.objectStore(name);
  11. const putIndex = putStore.index('id');
  12. objects.forEach(object => {
  13. putIndex.getKey(object.id).onsuccess = retrieval => {
  14. function addObject() {
  15. putStore.add(object);
  16. }
  17. function deleteObject() {
  18. putStore.delete(retrieval.target.result).onsuccess = addObject;
  19. }
  20. if (retrieval.target.result) {
  21. if (onupdate) {
  22. onupdate(object, retrieval.target.result, putStore, deleteObject);
  23. } else {
  24. deleteObject();
  25. }
  26. } else {
  27. if (oncreate) {
  28. oncreate(object, addObject);
  29. } else {
  30. addObject();
  31. }
  32. }
  33. };
  34. });
  35. putTransaction.oncomplete = () => {
  36. const readTransaction = db.transaction(name, 'readonly');
  37. const readStore = readTransaction.objectStore(name);
  38. const count = readStore.count();
  39. count.onsuccess = () => {
  40. const excess = count.result - limit;
  41. if (excess > 0) {
  42. const retrieval = readStore.getAll(null, excess);
  43. retrieval.onsuccess = () => resolve(retrieval.result);
  44. retrieval.onerror = reject;
  45. } else {
  46. resolve([]);
  47. }
  48. };
  49. count.onerror = reject;
  50. };
  51. putTransaction.onerror = reject;
  52. }));
  53. }
  54. function evictAccountsByRecords(records) {
  55. asyncDB.then(db => {
  56. const transaction = db.transaction(['accounts', 'statuses'], 'readwrite');
  57. const accounts = transaction.objectStore('accounts');
  58. const accountsIdIndex = accounts.index('id');
  59. const accountsMovedIndex = accounts.index('moved');
  60. const statuses = transaction.objectStore('statuses');
  61. const statusesIndex = statuses.index('account');
  62. function evict(toEvict) {
  63. toEvict.forEach(record => {
  64. asyncCache.then(cache => accountAssetKeys.forEach(key => cache.delete(records[key])));
  65. accountsMovedIndex.getAll(record.id).onsuccess = ({ target }) => evict(target.result);
  66. statusesIndex.getAll(record.id).onsuccess =
  67. ({ target }) => evictStatusesByRecords(target.result);
  68. accountsIdIndex.getKey(record.id).onsuccess =
  69. ({ target }) => target.result && accounts.delete(target.result);
  70. });
  71. }
  72. evict(records);
  73. });
  74. }
  75. export function evictStatus(id) {
  76. return evictStatuses([id]);
  77. }
  78. export function evictStatuses(ids) {
  79. asyncDB.then(db => {
  80. const store = db.transaction('statuses', 'readwrite').objectStore('statuses');
  81. const idIndex = store.index('id');
  82. const reblogIndex = store.index('reblog');
  83. ids.forEach(id => {
  84. reblogIndex.getAllKeys(id).onsuccess =
  85. ({ target }) => target.result.forEach(reblogKey => store.delete(reblogKey));
  86. idIndex.getKey(id).onsuccess =
  87. ({ target }) => target.result && store.delete(target.result);
  88. });
  89. });
  90. }
  91. function evictStatusesByRecords(records) {
  92. evictStatuses(records.map(({ id }) => id));
  93. }
  94. export function putAccounts(records) {
  95. const newURLs = [];
  96. put('accounts', records, (newRecord, oldKey, store, oncomplete) => {
  97. store.get(oldKey).onsuccess = ({ target }) => {
  98. accountAssetKeys.forEach(key => {
  99. const newURL = newRecord[key];
  100. const oldURL = target.result[key];
  101. if (newURL !== oldURL) {
  102. asyncCache.then(cache => cache.delete(oldURL));
  103. }
  104. });
  105. const newURL = newRecord[avatarKey];
  106. const oldURL = target.result[avatarKey];
  107. if (newURL !== oldURL) {
  108. newURLs.push(newURL);
  109. }
  110. oncomplete();
  111. };
  112. }, (newRecord, oncomplete) => {
  113. newURLs.push(newRecord[avatarKey]);
  114. oncomplete();
  115. }).then(records => {
  116. evictAccountsByRecords(records);
  117. asyncCache.then(cache => cache.addAll(newURLs));
  118. });
  119. }
  120. export function putStatuses(records) {
  121. put('statuses', records).then(evictStatusesByRecords);
  122. }