Source: encrypt/indexeddb-producer-db.js

  1. /**
  2. * Copyright (C) 2015-2016 Regents of the University of California.
  3. * @author: Jeff Thompson <jefft0@remap.ucla.edu>
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Lesser General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. * A copy of the GNU Lesser General Public License is in the file COPYING.
  18. */
  19. // Don't require modules since this is meant for the browser, not Node.js.
  20. /**
  21. * IndexedDbProducerDb extends ProducerDb to implement storage of keys for the
  22. * producer using the browser's IndexedDB service. It contains one table that
  23. * maps time slots (to the nearest hour) to the content key created for that
  24. * time slot.
  25. * Create an IndexedDbProducerDb to use the given IndexedDB database name.
  26. * @param {string} databaseName IndexedDB database name.
  27. * @note This class is an experimental feature. The API may change.
  28. * @constructor
  29. */
  30. var IndexedDbProducerDb = function IndexedDbProducerDb(databaseName)
  31. {
  32. ProducerDb.call(this);
  33. this.database = new Dexie(databaseName);
  34. this.database.version(1).stores({
  35. // "timeSlot" is the hour-based time slot as hours since Jan 1, 1970 UTC. // number
  36. // "key" is the encoded key // Uint8Array
  37. contentKeys: "timeSlot"
  38. });
  39. this.database.open();
  40. };
  41. IndexedDbProducerDb.prototype = new ProducerDb();
  42. IndexedDbProducerDb.prototype.name = "IndexedDbProducerDb";
  43. /**
  44. * Check if a content key exists for the hour covering timeSlot.
  45. * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
  46. * @param {boolean} useSync (optional) If true then return a rejected promise
  47. * since this only supports async code.
  48. * @return {Promise} A promise that returns true if there is a content key for
  49. * timeSlot (else false), or that is rejected with ProducerDb.Error for a
  50. * database error.
  51. */
  52. IndexedDbProducerDb.prototype.hasContentKeyPromise = function(timeSlot, useSync)
  53. {
  54. if (useSync)
  55. return Promise.reject(new ProducerDb.Error(new Error
  56. ("IndexedDbProducerDb.hasContentKeyPromise is only supported for async")));
  57. var fixedTimeSlot = ProducerDb.getFixedTimeSlot(timeSlot);
  58. return this.database.contentKeys.get(fixedTimeSlot)
  59. .then(function(contentKeysEntry) {
  60. return Promise.resolve(contentKeysEntry != undefined);
  61. })
  62. .catch(function(ex) {
  63. return Promise.reject(new ProducerDb.Error(new Error
  64. ("IndexedDbProducerDb.hasContentKeyPromise: Error: " + ex)));
  65. });
  66. };
  67. /**
  68. * Get the content key for the hour covering timeSlot.
  69. * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
  70. * @param {boolean} useSync (optional) If true then return a rejected promise
  71. * since this only supports async code.
  72. * @return {Promise} A promise that returns a Blob with the encoded key, or that
  73. * is rejected with ProducerDb.Error if there is no key covering timeSlot, or
  74. * other database error
  75. */
  76. IndexedDbProducerDb.prototype.getContentKeyPromise = function(timeSlot, useSync)
  77. {
  78. if (useSync)
  79. return Promise.reject(new ProducerDb.Error(new Error
  80. ("IndexedDbProducerDb.getContentKeyPromise is only supported for async")));
  81. var fixedTimeSlot = ProducerDb.getFixedTimeSlot(timeSlot);
  82. return this.database.contentKeys.get(fixedTimeSlot)
  83. .then(function(contentKeysEntry) {
  84. if (contentKeysEntry)
  85. return Promise.resolve(new Blob(contentKeysEntry.key));
  86. else
  87. return Promise.reject(new ProducerDb.Error(new Error
  88. ("IndexedDbProducerDb.getContentKeyPromise: Cannot get the key from the database")));
  89. }, function(ex) {
  90. return Promise.reject(new ProducerDb.Error(new Error
  91. ("IndexedDbProducerDb.getContentKeyPromise: Error: " + ex)));
  92. });
  93. };
  94. /**
  95. * Add key as the content key for the hour covering timeSlot.
  96. * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
  97. * @param {Blob} key The encoded key.
  98. * @param {boolean} useSync (optional) If true then return a rejected promise
  99. * since this only supports async code.
  100. * @return {Promise} A promise that fulfills when the key is added, or that
  101. * is rejected with ProducerDb.Error if a key for the same hour already exists
  102. * in the database, or other database error.
  103. */
  104. IndexedDbProducerDb.prototype.addContentKeyPromise = function
  105. (timeSlot, key, useSync)
  106. {
  107. if (useSync)
  108. return Promise.reject(new ProducerDb.Error(new Error
  109. ("IndexedDbProducerDb.addContentKeyPromise is only supported for async")));
  110. var fixedTimeSlot = ProducerDb.getFixedTimeSlot(timeSlot);
  111. // Add rejects if the primary key already exists.
  112. return this.database.contentKeys.add
  113. ({ timeSlot: fixedTimeSlot, key: key.buf() })
  114. .catch(function(ex) {
  115. return Promise.reject(new ProducerDb.Error(new Error
  116. ("IndexedDbProducerDb.addContentKeyPromise: Error: " + ex)));
  117. });
  118. };
  119. /**
  120. * Delete the content key for the hour covering timeSlot. If there is no key for
  121. * the time slot, do nothing.
  122. * @param {number} timeSlot The time slot as milliseconds since Jan 1, 1970 UTC.
  123. * @param {boolean} useSync (optional) If true then return a rejected promise
  124. * since this only supports async code.
  125. * @return {Promise} A promise that fulfills when the key is deleted (or there
  126. * is no such key), or that is rejected with ProducerDb.Error for a database
  127. * error.
  128. */
  129. IndexedDbProducerDb.prototype.deleteContentKeyPromise = function(timeSlot, useSync)
  130. {
  131. if (useSync)
  132. return Promise.reject(new ProducerDb.Error(new Error
  133. ("IndexedDbProducerDb.deleteContentKeyPromise is only supported for async")));
  134. var fixedTimeSlot = ProducerDb.getFixedTimeSlot(timeSlot);
  135. return this.database.contentKeys.delete(fixedTimeSlot)
  136. .catch(function(ex) {
  137. return Promise.reject(new ProducerDb.Error(new Error
  138. ("IndexedDbProducerDb.deleteContentKeyPromise: Error: " + ex)));
  139. });
  140. };