PersistentCache.jsm 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
  6. ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
  7. XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
  8. /**
  9. * A file (disk) based persistent cache of a JSON serializable object.
  10. */
  11. this.PersistentCache = class PersistentCache {
  12. /**
  13. * Create a cache object based on a name.
  14. *
  15. * @param {string} name Name of the cache. It will be used to create the filename.
  16. * @param {boolean} preload (optional). Whether the cache should be preloaded from file. Defaults to false.
  17. */
  18. constructor(name, preload = false) {
  19. this.name = name;
  20. this._filename = `activity-stream.${name}.json`;
  21. if (preload) {
  22. this._load();
  23. }
  24. }
  25. /**
  26. * Set a value to be cached with the specified key.
  27. *
  28. * @param {string} key The cache key.
  29. * @param {object} value The data to be cached.
  30. */
  31. async set(key, value) {
  32. const data = await this._load();
  33. data[key] = value;
  34. await this._persist(data);
  35. }
  36. /**
  37. * Get a value from the cache.
  38. *
  39. * @param {string} key (optional) The cache key. If not provided, we return the full cache.
  40. * @returns {object} The cached data.
  41. */
  42. async get(key) {
  43. const data = await this._load();
  44. return key ? data[key] : data;
  45. }
  46. /**
  47. * Load the cache into memory if it isn't already.
  48. */
  49. _load() {
  50. return this._cache || (this._cache = new Promise(async resolve => {
  51. let file;
  52. let data = {};
  53. const filepath = OS.Path.join(OS.Constants.Path.localProfileDir, this._filename);
  54. try {
  55. file = await fetch(`file://${filepath}`);
  56. } catch (error) {} // Cache file doesn't exist yet.
  57. if (file) {
  58. try {
  59. data = await file.json();
  60. } catch (error) {
  61. Cu.reportError(`Failed to parse ${this._filename}: ${error.message}`);
  62. }
  63. }
  64. resolve(data);
  65. }));
  66. }
  67. /**
  68. * Persist the cache to file.
  69. */
  70. _persist(data) {
  71. const filepath = OS.Path.join(OS.Constants.Path.localProfileDir, this._filename);
  72. return OS.File.writeAtomic(filepath, JSON.stringify(data), {tmpPath: `${filepath}.tmp`});
  73. }
  74. };
  75. const EXPORTED_SYMBOLS = ["PersistentCache"];