indexed-db.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. "use strict";
  2. /*global indexedDB*/
  3. var codec = require('../lib/object-codec.js');
  4. var sha1 = require('git-sha1');
  5. var modes = require('../lib/modes.js');
  6. var db;
  7. mixin.init = init;
  8. mixin.loadAs = loadAs;
  9. mixin.saveAs = saveAs;
  10. module.exports = mixin;
  11. function init(callback) {
  12. db = null;
  13. var request = indexedDB.open("tedit", 1);
  14. // We can only create Object stores in a versionchange transaction.
  15. request.onupgradeneeded = function(evt) {
  16. var db = evt.target.result;
  17. if (evt.dataLoss && evt.dataLoss !== "none") {
  18. return callback(new Error(evt.dataLoss + ": " + evt.dataLossMessage));
  19. }
  20. // A versionchange transaction is started automatically.
  21. evt.target.transaction.onerror = onError;
  22. if(db.objectStoreNames.contains("objects")) {
  23. db.deleteObjectStore("objects");
  24. }
  25. if(db.objectStoreNames.contains("refs")) {
  26. db.deleteObjectStore("refs");
  27. }
  28. db.createObjectStore("objects", {keyPath: "hash"});
  29. db.createObjectStore("refs", {keyPath: "path"});
  30. };
  31. request.onsuccess = function (evt) {
  32. db = evt.target.result;
  33. callback();
  34. };
  35. request.onerror = onError;
  36. }
  37. function mixin(repo, prefix) {
  38. if (!prefix) throw new Error("Prefix required");
  39. repo.refPrefix = prefix;
  40. repo.saveAs = saveAs;
  41. repo.loadAs = loadAs;
  42. repo.readRef = readRef;
  43. repo.updateRef = updateRef;
  44. repo.hasHash = hasHash;
  45. }
  46. function onError(evt) {
  47. console.error("error", evt.target.error);
  48. }
  49. function saveAs(type, body, callback, forcedHash) {
  50. if (!callback) return saveAs.bind(this, type, body);
  51. var hash;
  52. try {
  53. var buffer = codec.frame({type:type,body:body});
  54. hash = forcedHash || sha1(buffer);
  55. }
  56. catch (err) { return callback(err); }
  57. var trans = db.transaction(["objects"], "readwrite");
  58. var store = trans.objectStore("objects");
  59. var entry = { hash: hash, type: type, body: body };
  60. var request = store.put(entry);
  61. request.onsuccess = function() {
  62. // console.warn("SAVE", type, hash);
  63. callback(null, hash, body);
  64. };
  65. request.onerror = function(evt) {
  66. callback(new Error(evt.value));
  67. };
  68. }
  69. function loadAs(type, hash, callback) {
  70. if (!callback) return loadAs.bind(this, type, hash);
  71. loadRaw(hash, function (err, entry) {
  72. if (!entry) return callback(err);
  73. if (type !== entry.type) {
  74. return callback(new TypeError("Type mismatch"));
  75. }
  76. callback(null, entry.body, hash);
  77. });
  78. }
  79. function loadRaw(hash, callback) {
  80. var trans = db.transaction(["objects"], "readwrite");
  81. var store = trans.objectStore("objects");
  82. var request = store.get(hash);
  83. request.onsuccess = function(evt) {
  84. var entry = evt.target.result;
  85. if (!entry) return callback();
  86. return callback(null, entry);
  87. };
  88. request.onerror = function(evt) {
  89. callback(new Error(evt.value));
  90. };
  91. }
  92. function hasHash(hash, callback) {
  93. if (!callback) return hasHash.bind(this, hash);
  94. loadRaw(hash, function (err, body) {
  95. if (err) return callback(err);
  96. return callback(null, !!body);
  97. });
  98. }
  99. function readRef(ref, callback) {
  100. if (!callback) return readRef.bind(this, ref);
  101. var key = this.refPrefix + "/" + ref;
  102. var trans = db.transaction(["refs"], "readwrite");
  103. var store = trans.objectStore("refs");
  104. var request = store.get(key);
  105. request.onsuccess = function(evt) {
  106. var entry = evt.target.result;
  107. if (!entry) return callback();
  108. callback(null, entry.hash);
  109. };
  110. request.onerror = function(evt) {
  111. callback(new Error(evt.value));
  112. };
  113. }
  114. function updateRef(ref, hash, callback) {
  115. if (!callback) return updateRef.bind(this, ref, hash);
  116. var key = this.refPrefix + "/" + ref;
  117. var trans = db.transaction(["refs"], "readwrite");
  118. var store = trans.objectStore("refs");
  119. var entry = { path: key, hash: hash };
  120. var request = store.put(entry);
  121. request.onsuccess = function() {
  122. callback();
  123. };
  124. request.onerror = function(evt) {
  125. callback(new Error(evt.value));
  126. };
  127. }