ndn-js-contrib
Version:
Reusable 'Classes' for Named Data Networking: NameTree, PIT, FIB, ContentStore, Interfaces, and Transports
144 lines (143 loc) • 5.24 kB
JavaScript
var leveldown = require("leveldown"),
levelup = require("levelup"),
Name = require("ndn-js/js/name.js").Name,
crypto = require("ndn-js/js/crypto.js"),
Data = require("ndn-js/js/data.js").Data,
NameTree = require("./NameTree.js"),
ContentStore = require("./ContentStore.js");
function Repository(path) {
var self = this;
this._dataPath = path;
this._contentStore = new ContentStore();
this._contentStore.setEntryClass(Repository.Entry);
return new Promise(function Repository_Constructor_Promise(resolve, reject) {
levelup(self._dataPath, {
db: leveldown,
valueEncoding: "json"
}, function Repository_Contstructor_Promise_levelup(err, db) {
if (err)
return reject(err);
self._dataDB = db;
self.populateContentStoreNodes().then(function() {
resolve(self);
}).catch(reject);
});
});
}
Repository.Open = function Repository_Open(path) {
return new Repository(path);
};
Repository.Entry = function Repository_Entry(data, repository) {
var self = this;
this._repository = repository;
this.prefix = data.name;
return this;
};
function Repository_getNameWithDigest(name, packet) {
var name = new Name(name);
name.append("sha256digest=" + crypto.createHash('sha256').update(packet).digest().toString('hex'));
return name;
}
Repository.Entry.prototype.getData = function Repository_Entry_getData() {
var self = this;
return new Promise(function Repository_Entry_getData_Promise(resolve, reject) {
self._repository._dataDB.get(self.prefix.toUri(), function(err, packet) {
if (err)
return reject(err);
var data = new Data();
data.wireDecode(new Buffer(packet));
resolve(data);
});
});
};
Repository.Entry.prototype.delete = function Repository_Entry_delete() {
var self = this;
return new Promise(function Repository_Entry_delete_Promise(resolve, reject) {
self._repository._dataDB.del(self.prefix.toUri(), function(err) {
if (err)
return reject(err);
resolve(self);
});
});
};
Repository.Entry.prototype.fulfillsInterest = function Repository_Entry_fulfillsInterest(interest) {
return (!!this.prefix && interest.matchesName(this.prefix));
};
Repository.prototype.createNode = function Repository_createNode(data, repository) {
var self = this;
return new Promise(function Repository_createNode_Promise(resolve, reject) {
var entry = new Repository.Entry(data, repository);
entry._repository = self;
if (!data.content) {
if (data.name.get(-1).toEscapedString().substr(0, 12) !== "sha256digest")
reject(new Error("new Repository.Entry(data, contentStore) : no content to digest or digest component on name" + data.name.toUri()));
resolve(new NameTree.Node(data.name, entry));
} else {
var packet = data.wireEncode().buffer,
nameWithDigest = Repository_getNameWithDigest(data.name, packet);
entry._repository._dataDB.put(nameWithDigest.toUri(), data.wireEncode().buffer, function(err) {
if (err)
reject(err);
else {
entry.prefix = nameWithDigest;
resolve(new NameTree.Node(entry.prefix, entry));
}
});
}
});
};
Repository.prototype.insert = function Repository_insert(data) {
return this._contentStore.insert(data, this);
};
Repository.prototype.remove = function Repository_remove(entry) {
var self = this;
return new Promise(function Repository_remove_Promise(resolve, reject) {
self._contentStore.nameTree.remove(entry.prefix);
entry.delete().then(resolve).catch(reject);
});
};
Repository.prototype.lookup = function Repository_lookup(interest) {
return this._contentStore.lookup(interest);
};
Repository.prototype.populateContentStoreNodes = function Repository_populateContentStoreNodes() {
var self = this;
return new Promise(function Repository_populateContentStoreNodes_Promise(resolve, reject) {
var proms = [];
self._dataDB.createKeyStream().on("data", function(key) {
proms.push(self.createNode({name: new Name(key)}, self).then(function(node) {
return self._contentStore._nameTree.insert(node);
}));
}).on("error", function(err) {
reject(err);
}).on("close", function() {}).on("end", function() {
Promise.all(proms).then(resolve).catch(function(err) {
self.close().then(function() {
reject(err);
});
});
});
});
};
Repository.prototype.close = function Repository_close() {
var self = this;
return new Promise(function Repository_close_Promise(resolve, reject) {
self._dataDB.close(function Repository_close_Promise_level(err) {
if (err)
return reject(err);
resolve(self);
});
});
};
Repository.prototype.destroy = function Repository_destroy() {
var self = this;
return new Promise(function Repository_destroy_Promise(resolve, reject) {
if (self._dataDB.isOpen())
return reject(new Error("Repository.destroy(): Repository must call Repository.close() prior to destruction"));
leveldown.destroy(self._dataPath, function Repository_destroy_level(err) {
if (!err)
return resolve();
reject(err);
});
});
};
module.exports = Repository;