Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

k-bucket

Package Overview
Dependencies
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

k-bucket - npm Package Compare versions

Comparing version 2.0.1 to 3.0.0

benchmarks/distance.js

159

index.js

@@ -7,3 +7,3 @@ /*

Copyright (c) 2013-2015 Tristan Slominski
Copyright (c) 2013-2016 Tristan Slominski

@@ -34,3 +34,5 @@ Permission is hereby granted, free of charge, to any person

var bufferEqual = require('buffer-equal');
var bufferEquals = require('buffer-equals');
var EventEmitter = require('events').EventEmitter;
var inherits = require('inherits');
var randomBytes = require('randombytes');

@@ -52,13 +54,11 @@

ping when a bucket that should not be split becomes full. KBucket will
call the `ping` callback that contains `numberOfNodesToPing` nodes that have
emit a `ping` event that contains `numberOfNodesToPing` nodes that have
not been contacted the longest.
* `ping`: _Function_ _(Default: no-op)_
`function (oldContacts, newContact) {}` Callback called every time a
contact is added that would exceed the capacity of a don't split k-bucket it belongs to.
* `oldContacts`: _Array_ The array of contacts to ping.
* `newContact`: _Object_ The new contact to be added if one of old contacts
does not respond.
* `root`: _Object_ _**CAUTION: reserved for internal use**_ Provides a
reference to the root of the tree data structure as the k-bucket splits
when new contacts are added.
*/
var KBucket = module.exports = function KBucket (options) {
var self = this;
EventEmitter.call(self);
options = options || {};

@@ -83,3 +83,3 @@

self.numberOfNodesToPing = options.numberOfNodesToPing || 3;
self.ping = options.ping || function() {};
self.root = options.root || self;

@@ -92,2 +92,4 @@ // V8 hints

inherits(KBucket, EventEmitter);
KBucket.distance = function distance (firstId, secondId) {

@@ -109,3 +111,3 @@ var distance = 0;

// the binary tree
KBucket.prototype.add = function add (contact, bitIndex) {
KBucket.prototype._add = function (contact, bitIndex) {
var self = this;

@@ -118,8 +120,6 @@

// delegate to the appropriate node for further processing
bitIndex = bitIndex || 0;
if (self.determineBucket(contact.id, bitIndex++) < 0) {
return self.low.add(contact, bitIndex);
if (self._determineBucket(contact.id, bitIndex++) < 0) {
return self.low._add(contact, bitIndex);
} else {
return self.high.add(contact, bitIndex);
return self.high._add(contact, bitIndex);
}

@@ -129,5 +129,5 @@ }

// check if the contact already exists
var index = self.indexOf(contact);
var index = self._indexOf(contact.id);
if (index >= 0) {
self.update(contact, index);
self._update(contact, index);
return self;

@@ -138,2 +138,3 @@ }

self.bucket.push(contact);
self.emit('added', contact);
return self;

@@ -149,15 +150,22 @@ }

// be added (this prevents DoS flodding with new invalid contacts)
self.ping(self.bucket.slice(0, self.numberOfNodesToPing), contact);
self.root.emit('ping', self.bucket.slice(0, self.numberOfNodesToPing), contact);
return self;
}
return self.splitAndAdd(contact, bitIndex);
return self._splitAndAdd(contact, bitIndex);
};
// contact: Object *required* contact object
// id: Buffer *require* node id
// contact: *required* the contact object to add
KBucket.prototype.add = function add (contact) {
if (!Buffer.isBuffer(contact.id)) {
throw new TypeError("contact.id is not a Buffer");
}
return this._add(contact, 0);
};
// id: Buffer *required* node id
// n: Integer *required* maximum number of closest contacts to return
// bitIndex: Integer (Default: 0)
// Return: Array of maximum of `n` closest contacts to the `contact`
KBucket.prototype.closest = function closest (contact, n, bitIndex) {
// Return: Array of maximum of `n` closest contacts to the node id
KBucket.prototype._closest = function (id, n, bitIndex) {
var self = this;

@@ -168,13 +176,11 @@

if (!self.bucket) {
bitIndex = bitIndex || 0;
if (self.determineBucket(contact.id, bitIndex++) < 0) {
contacts = self.low.closest(contact, n, bitIndex);
if (self._determineBucket(id, bitIndex++) < 0) {
contacts = self.low._closest(id, n, bitIndex);
if (contacts.length < n) {
contacts = contacts.concat(self.high.closest(contact, n, bitIndex));
contacts = contacts.concat(self.high._closest(id, n, bitIndex));
}
} else {
contacts = self.high.closest(contact, n, bitIndex);
contacts = self.high._closest(id, n, bitIndex);
if (contacts.length < n) {
contacts = contacts.concat(self.low.closest(contact, n, bitIndex));
contacts = contacts.concat(self.low._closest(id, n, bitIndex));
}

@@ -187,3 +193,3 @@ }

contacts.forEach(function (storedContact) {
storedContact.distance = KBucket.distance(storedContact.id, contact.id);
storedContact.distance = KBucket.distance(storedContact.id, id);
});

@@ -196,2 +202,12 @@

// id: Buffer *required* node id
// n: Integer *required* maximum number of closest contacts to return
// Return: Array of maximum of `n` closest contacts to the node id
KBucket.prototype.closest = function (id, n) {
if (!Buffer.isBuffer(id)) {
throw new TypeError("id is not a Buffer");
}
return this._closest(id, n, 0);
};
// Counts the number of contacts recursively.

@@ -213,3 +229,3 @@ // If this is a leaf, just return the number of contacts contained. Otherwise,

// bitIndex: the bitIndex to which bit to check in the id Buffer
KBucket.prototype.determineBucket = function determineBucket (id, bitIndex) {
KBucket.prototype._determineBucket = function (id, bitIndex) {
var self = this;

@@ -255,19 +271,17 @@

// which branch of the tree to traverse and repeat.
// id: *required* a Buffer specifying the ID of the contact to fetch
// id: Buffer *required* The ID of the contact to fetch.
// bitIndex: the bitIndex to which bit to check in the Buffer for navigating
// the binary tree
KBucket.prototype.get = function get (id, bitIndex) {
KBucket.prototype._get = function (id, bitIndex) {
var self = this;
if (!self.bucket) {
bitIndex = bitIndex || 0;
if (self.determineBucket(id, bitIndex++) < 0) {
return self.low.get(id, bitIndex);
if (self._determineBucket(id, bitIndex++) < 0) {
return self.low._get(id, bitIndex);
} else {
return self.high.get(id, bitIndex);
return self.high._get(id, bitIndex);
}
}
var index = self.indexOf({id: id}); // index of uses contact.id for matching
var index = self._indexOf(id); // index of uses contact id for matching
if (index < 0) {

@@ -280,8 +294,19 @@ return null; // contact not found

// Returns the index of the contact if it exists
// **NOTE**: indexOf() does not compare vectorClock
KBucket.prototype.indexOf = function indexOf (contact) {
// Get a contact by its exact ID.
// If this is a leaf, loop through the bucket contents and return the correct
// contact if we have it or null if not. If this is an inner node, determine
// which branch of the tree to traverse and repeat.
// id: Buffer *required* The ID of the contact to fetch.
KBucket.prototype.get = function get (id) {
if (!Buffer.isBuffer(id)) {
throw new TypeError("id is not a Buffer");
}
return this._get(id, 0);
};
// Returns the index of the contact with the given id if it exists
KBucket.prototype._indexOf = function indexOf (id) {
var self = this;
for (var i = 0; i < self.bucket.length; i++) {
if (bufferEqual(self.bucket[i].id, contact.id)) return i;
if (bufferEquals(self.bucket[i].id, id)) return i;
}

@@ -291,6 +316,6 @@ return -1;

// contact: *required* the contact object to remove
// id: Buffer *required* The ID of the contact to remove.
// bitIndex: the bitIndex to which bit to check in the Buffer for navigating
// the binary tree
KBucket.prototype.remove = function remove (contact, bitIndex) {
KBucket.prototype._remove = function (id, bitIndex) {
var self = this;

@@ -303,16 +328,25 @@

// delegate to the appropriate node for further processing
bitIndex = bitIndex || 0;
if (self.determineBucket(contact.id, bitIndex++) < 0) {
return self.low.remove(contact, bitIndex);
if (self._determineBucket(id, bitIndex++) < 0) {
return self.low._remove(id, bitIndex);
} else {
return self.high.remove(contact, bitIndex);
return self.high._remove(id, bitIndex);
}
}
var index = self.indexOf(contact);
if (index >= 0) self.bucket.splice(index, 1);
var index = self._indexOf(id);
if (index >= 0) {
var contact = self.bucket.splice(index, 1)[0];
self.emit('removed', contact);
}
return self;
};
// id: Buffer *required* he ID of the contact to remove.
KBucket.prototype.remove = function remove (id) {
if (!Buffer.isBuffer(id)) {
throw new TypeError("id is not a Buffer");
}
return this._remove(id, 0);
};
// Splits the bucket, redistributes contacts to the new buckets, and marks the

@@ -324,3 +358,3 @@ // bucket that was split as an inner node of the binary tree of buckets by

// binary tree
KBucket.prototype.splitAndAdd = function splitAndAdd (contact, bitIndex) {
KBucket.prototype._splitAndAdd = function (contact, bitIndex) {
var self = this;

@@ -332,3 +366,3 @@ self.low = new KBucket({

numberOfNodesToPing: self.numberOfNodesToPing,
ping: self.ping
root: self.root
});

@@ -340,3 +374,3 @@ self.high = new KBucket({

numberOfNodesToPing: self.numberOfNodesToPing,
ping: self.ping
root: self.root
});

@@ -348,3 +382,3 @@

self.bucket.forEach(function (storedContact) {
if (self.determineBucket(storedContact.id, bitIndex) < 0) {
if (self._determineBucket(storedContact.id, bitIndex) < 0) {
self.low.add(storedContact);

@@ -361,3 +395,3 @@ } else {

// "dontSplit" (i.e. "far away")
if (self.determineBucket(self.localNodeId, bitIndex) < 0) {
if (self._determineBucket(self.localNodeId, bitIndex) < 0) {
// local node belongs to "low" bucket, so mark the other one

@@ -370,3 +404,3 @@ self.high.dontSplit = true;

// add the contact being added
self.add(contact, bitIndex);
self._add(contact, bitIndex);

@@ -402,6 +436,6 @@ return self;

// (index has already been computed in a previous calculation)
KBucket.prototype.update = function update (contact, index) {
KBucket.prototype._update = function (contact, index) {
var self = this;
// sanity check
if (!bufferEqual(self.bucket[index].id, contact.id)) {
if (!bufferEquals(self.bucket[index].id, contact.id)) {
throw new Error("indexOf() calculation resulted in wrong index")

@@ -420,2 +454,3 @@ }

self.bucket.push(selection); // add more recent contact version
self.emit('updated', incumbent, selection);
};
{
"name": "k-bucket",
"version": "2.0.1",
"version": "3.0.0",
"description": "Kademlia DHT K-bucket implementation as a binary tree",
"scripts": {
"distance-benchmark": "node benchmarks/distance.js",
"test": "node scripts/test.js"

@@ -13,3 +14,4 @@ },

"dependencies": {
"buffer-equal": "0.0.1",
"buffer-equals": "^1.0.3",
"inherits": "^2.0.1",
"randombytes": "^2.0.3"

@@ -16,0 +18,0 @@ },

@@ -41,3 +41,3 @@ # k-bucket

This *k-bucket* implementation implements a conflict resolution mechanism using an `arbiter` function. The purpose of the `arbiter` is to choose between two `contact` objects with the same `id` but perhaps different properties and determine which one should be stored. As the `arbiter` function returns the actual object to be stored, it does not need to make an either/or choice, but instead could perform some sort of operation and return the result as a new object that would then be stored. See [kBucket.update(contact, index)](#kbucketupdatecontact-index) for detailed semantics of which `contact` (`incumbent` or `candidate`) is selected.
This *k-bucket* implementation implements a conflict resolution mechanism using an `arbiter` function. The purpose of the `arbiter` is to choose between two `contact` objects with the same `id` but perhaps different properties and determine which one should be stored. As the `arbiter` function returns the actual object to be stored, it does not need to make an either/or choice, but instead could perform some sort of operation and return the result as a new object that would then be stored. See [kBucket._update(contact, index)](#kbucket_updatecontact-index) for detailed semantics of which `contact` (`incumbent` or `candidate`) is selected.

@@ -103,3 +103,3 @@ For example, an `arbiter` function implementing a `vectorClock` mechanism would look something like:

As more contacts are added to the "far" k-bucket and it reaches its capacity, it does not split. Instead, the k-bucket calls the "ping" callback (`function (oldContacts, newContact) {...});` and includes an array of old contact nodes that it hasn't heard from in a while and requires you to confirm that those contact nodes still respond (literally respond to a PING RPC). If an old contact node still responds, it should be re-added (`kBucket.add(oldContact)`) back to the k-bucket. This puts the old contact on the "recently heard from" end of the list of nodes in the k-bucket. If the old contact does not respond, it should be removed (`kBucket.remove(oldContact)`) and the new contact being added now has room to be stored (`kBucket.add(newContact)`).
As more contacts are added to the "far" k-bucket and it reaches its capacity, it does not split. Instead, the k-bucket emits a "ping" event (register a listener: `kBucket.on('ping', function (oldContacts, newContact) {...});` and includes an array of old contact nodes that it hasn't heard from in a while and requires you to confirm that those contact nodes still respond (literally respond to a PING RPC). If an old contact node still responds, it should be re-added (`kBucket.add(oldContact)`) back to the k-bucket. This puts the old contact on the "recently heard from" end of the list of nodes in the k-bucket. If the old contact does not respond, it should be removed (`kBucket.remove(oldContact.id)`) and the new contact being added now has room to be stored (`kBucket.add(newContact)`).

@@ -109,8 +109,12 @@ **Public API**

* [new KBucket(options)](#new-kbucketoptions)
* [kBucket.add(contact, \[bitIndex\])](#kbucketaddcontact-bitindex)
* [kBucket.closest(contact, n, \[bitIndex\])](#kbucketclosestcontact-n-bitindex)
* [kBucket.add(contact)](#kbucketaddcontact)
* [kBucket.closest(id, n)](#kbucketclosestid-n)
* [kBucket.count()](#kbucketcount)
* [kBucket.get(id, \[bitIndex\])](#kbucketgetid-bitindex)
* [kBucket.remove(contact, \[bitIndex\])](#kbucketremovecontact-bitindex)
* [kBucket.get(id)](#kbucketgetid)
* [kBucket.remove(id)](#kbucketremoveid)
* [kBucket.toArray()](#kbuckettoarray)
* [Event 'added'](#event-added)
* [Event 'ping'](#event-ping)
* [Event 'removed'](#event-removed)
* [Event 'updated'](#event-updated)

@@ -132,11 +136,8 @@ #### KBucket.distance(firstId, secondId)

* `numberOfNodesPerKBucket`: _Integer_ _(Default: 20)_ The number of nodes that a k-bucket can contain before being full or split.
* `numberOfNodesToPing`: _Integer_ _(Default: 3)_ The number of nodes to ping when a bucket that should not be split becomes full. KBucket will call the `ping` callback that contains `numberOfNodesToPing` nodes that have not been contacted the longest.
* `ping`: _Function_ _(Default: no-op)_
`function (oldContacts, newContact) {}` Callback called every time a contact is added that would exceed the capacity of a don't split k-bucket it belongs to.
* `oldContacts`: _Array_ The array of contacts to ping.
* `newContact`: _Object_ The new contact to be added if one of old contacts does not respond.
* `numberOfNodesToPing`: _Integer_ _(Default: 3)_ The number of nodes to ping when a bucket that should not be split becomes full. KBucket will emit a `ping` event that contains `numberOfNodesToPing` nodes that have not been contacted the longest.
* `root`: _Object_ _**CAUTION: reserved for internal use**_ Provides a reference to the root of the tree data structure as the k-bucket splits when new contacts are added.
Creates a new KBucket.
#### kBucket.add(contact, [bitIndex])
#### kBucket.add(contact)

@@ -146,3 +147,2 @@ * `contact`: _Object_ The contact object to add.

* Any satellite data that is part of the `contact` object will not be altered, only `id` is used.
* `bitIndex`: _Integer_ _(Default: 0)_ _**CAUTION: reserved for internal use**_ The bit index to which bit to check in the `id` Buffer.
* Return: _Object_ The k-bucket itself.

@@ -152,12 +152,9 @@

#### kBucket.closest(contact, n, [bitIndex])
#### kBucket.closest(id, n)
* `contact`: _Object_ The contact object to find closest contacts to.
* `id`: _Buffer_ Contact node id.
* Any satellite data that is part of the `contact` object will not be altered, only `id` is used.
* `id`: _Buffer_ Contact node id.
* `n`: _Integer_ The maximum number of closest contacts to return.
* `bitIndex`: _Integer_ _(Default: 0)_ _**CAUTION: reserved for internal use**_ The bit index to which bit to check in the `id` Buffer.
* Return: _Array_ Maximum of `n` closest contacts to the `contact`.
* Return: _Array_ Maximum of `n` closest contacts to the node id.
Get the `n` closest contacts to the provided `contact`. "Closest" here means: closest according to the XOR metric of the `contact` node id.
Get the `n` closest contacts to the provided node id. "Closest" here means: closest according to the XOR metric of the `contact` node id.

@@ -170,4 +167,24 @@ #### kBucket.count()

#### kBucket.determineBucket(id, [bitIndex])
#### kBucket.get(id)
* `id`: _Buffer_ The ID of the `contact` to fetch.
* Return: _Object_ The `contact` if available, otherwise null
Retrieves the `contact`.
#### kBucket.remove(id)
* `id`: _Buffer_ The ID of the `contact` to remove.
* Return: _Object_ The k-bucket itself.
Removes `contact` with the provided `id`.
#### kBucket.toArray()
* Return: _Array_ All of the contacts in the tree, as an array
Traverses the tree, putting all the contacts into one array.
#### kBucket._determineBucket(id, [bitIndex])
_**CAUTION: reserved for internal use**_

@@ -181,12 +198,4 @@

#### kBucket.get(id, [bitIndex])
#### kBucket._indexOf(contact)
* `id`: _Buffer_ The ID of the `contact` to fetch
* `bitIndex`: _Integer_ _(Default: 0)_ _**CAUTION: reserved for internal use**_ The bit index to which bit to check in the `id` Buffer.
* Return: _Object_ The `contact` if available, otherwise null
Retrieves the `contact`.
#### kBucket.indexOf(contact)
_**CAUTION: reserved for internal use**_

@@ -201,16 +210,6 @@

_NOTE: `kBucket.indexOf(contact)` does not use `arbiter` in the comparison.
_NOTE: `kBucket._indexOf(contact)` does not use `arbiter` in the comparison.
#### kBucket.remove(contact, [bitIndex])
#### kBucket._splitAndAdd(contact, [bitIndex])
* `contact`: _Object_ The contact object to remove.
* `id`: _Buffer_ contact node id.
* Any satellite data can be part of the `contact` object, only `id` is used
* `bitIndex`: _Integer_ _(Default: 0)_ _**CAUTION: reserved for internal use**_ The bit index to which bit to check in the `id` Buffer.
* Return: _Object_ The k-bucket itself.
Removes the `contact`.
#### kBucket.splitAndAdd(contact, [bitIndex])
_**CAUTION: reserved for internal use**_

@@ -226,10 +225,4 @@

#### kBucket.toArray()
#### kBucket._update(contact, index)
* Return: _Array_ All of the contacts in the tree, as an array
Traverses the tree, putting all the contacts into one array.
#### kBucket.update(contact, index)
_**CAUTION: reserved for internal use**_

@@ -244,2 +237,44 @@

#### Event: 'added'
* `newContact`: _Object_ The new contact that was added.
Emitted only when `newContact` was added to bucket and it was not stored in the bucket before.
#### Event: 'ping'
* `oldContacts`: _Array_ The array of contacts to ping.
* `newContact`: _Object_ The new contact to be added if one of old contacts does not respond.
Emitted every time a contact is added that would exceed the capacity of a _don't split_ k-bucket it belongs to.
#### Event: 'removed'
* `contact`: _Object_ The contact that was removed.
Emitted when `contact` was removed from the bucket.
#### Event: 'updated'
* `oldContact`: _Object_ The contact that was stored prior to the update.
* `newContact`: _Object_ The new contact that is now stored after the update.
Emitted when a previously existing ("previously existing" means `oldContact.id` equals `newContact.id`) contact was added to the bucket and it was replaced with `newContact`.
## Releases
[Current releases](https://github.com/tristanls/k-bucket/releases).
### Policy
We follow the semantic versioning policy ([semver.org](http://semver.org/)) with a caveat:
> Given a version number MAJOR.MINOR.PATCH, increment the:
>
>MAJOR version when you make incompatible API changes,<br/>
>MINOR version when you add functionality in a backwards-compatible manner, and<br/>
>PATCH version when you make backwards-compatible bug fixes.
**caveat**: Major version zero is a special case indicating development version that may make incompatible API changes without incrementing MAJOR version.
## Sources

@@ -250,2 +285,2 @@

- [A formal specification of the Kademlia distributed hash table](http://maude.sip.ucm.es/kademlia/files/pita_kademlia.pdf)
- [Distributed Hash Tables (part 2)](http://offthelip.org/?p=157)
- [Distributed Hash Tables (part 2)](https://web.archive.org/web/20140217064545/http://offthelip.org/?p=157)

@@ -7,2 +7,12 @@ "use strict";

test['throws TypeError if contact.id is not a Buffer'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: "foo"};
test.throws(function () {
kBucket.add(contact);
}, TypeError);
test.done();
};
test['adding a contact places it in bucket'] = function (test) {

@@ -48,3 +58,6 @@ test.expect(1);

test.expect(3 /*numberOfNodesToPing*/ + 2);
var ping = function (contacts, replacement) {
var kBucket = new KBucket({
localNodeId: new Buffer('0000', 'hex')
});
kBucket.on('ping', function (contacts, replacement) {
test.equal(contacts.length, kBucket.numberOfNodesToPing);

@@ -58,7 +71,3 @@ // console.dir(kBucket.high.bucket[0]);

test.done();
};
var kBucket = new KBucket({
localNodeId: new Buffer('0000', 'hex'),
ping: ping
});
})
for (var j = 0; j < kBucket.numberOfNodesPerKBucket + 1; j++) {

@@ -73,1 +82,13 @@ iString = j.toString('16');

};
test['should generate event "added" once'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: new Buffer("a")};
kBucket.on('added', function (newContact) {
test.deepEqual(newContact, contact);
});
kBucket.add(contact);
kBucket.add(contact);
test.done();
};

@@ -7,2 +7,12 @@ "use strict";

test['throws TypeError if contact.id is not a Buffer'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: "foo"};
test.throws(function () {
kBucket.closest(contact.id, 4);
}, TypeError);
test.done();
};
test['closest nodes are returned'] = function (test) {

@@ -30,3 +40,3 @@ test.expect(3);

var contact = {id: new Buffer('15', 'hex')};// 00010101
var contacts = kBucket.closest(contact, 3);
var contacts = kBucket.closest(contact.id, 3);
test.deepEqual(contacts[0].id, new Buffer('11', 'hex')); // distance: 00000100

@@ -60,3 +70,3 @@ test.deepEqual(contacts[1].id, new Buffer('10', 'hex')); // distance: 00000101

var contact = {id: new Buffer('11', 'hex')};// 00010001
var contacts = kBucket.closest(contact, 3);
var contacts = kBucket.closest(contact.id, 3);
test.deepEqual(contacts[0].id, new Buffer('11', 'hex')); // distance: 00000000

@@ -84,3 +94,3 @@ test.deepEqual(contacts[1].id, new Buffer('10', 'hex')); // distance: 00000001

var contact = {id: new Buffer('0003', 'hex')}; // 0000000000000011
var contacts = kBucket.closest(contact, 22);
var contacts = kBucket.closest(contact.id, 22);
test.deepEqual(contacts[0].id, new Buffer('0001', 'hex')); // distance: 0000000000000010

@@ -110,2 +120,2 @@ test.deepEqual(contacts[1].id, new Buffer('0103', 'hex')); // distance: 0000000100000000

test.done();
};
};
"use strict";
var bufferEqual = require('buffer-equal');
var EventEmitter = require('events').EventEmitter;

@@ -35,7 +36,14 @@ var KBucket = require('../index.js');

test['ping is \'Function\' if not provided'] = function (test) {
test['root is \'self\' if not provided'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.ok(kBucket.ping instanceof Function);
test.strictEqual(kBucket.root, kBucket);
test.done();
};
test['inherits from EventEmitter'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.ok(kBucket instanceof EventEmitter);
test.done();
};

@@ -10,3 +10,3 @@ "use strict";

var kBucket = new KBucket();
test.equal(kBucket.determineBucket(new Buffer("00", "hex"), 0), -1);
test.equal(kBucket._determineBucket(new Buffer("00", "hex"), 0), -1);
test.done();

@@ -18,3 +18,3 @@ };

var kBucket = new KBucket();
test.equal(kBucket.determineBucket(new Buffer("40", "hex"), 0), -1);
test.equal(kBucket._determineBucket(new Buffer("40", "hex"), 0), -1);
test.done();

@@ -26,3 +26,3 @@ };

var kBucket = new KBucket();
test.equal(kBucket.determineBucket(new Buffer("40", "hex"), 1), 1);
test.equal(kBucket._determineBucket(new Buffer("40", "hex"), 1), 1);
test.done();

@@ -34,3 +34,3 @@ };

var kBucket = new KBucket();
test.equal(kBucket.determineBucket(new Buffer("40", "hex"), 2), -1);
test.equal(kBucket._determineBucket(new Buffer("40", "hex"), 2), -1);
test.done();

@@ -42,3 +42,3 @@ };

var kBucket = new KBucket();
test.equal(kBucket.determineBucket(new Buffer("40", "hex"), 9), -1);
test.equal(kBucket._determineBucket(new Buffer("40", "hex"), 9), -1);
test.done();

@@ -50,3 +50,3 @@ };

var kBucket = new KBucket();
test.equal(kBucket.determineBucket(new Buffer("41", "hex"), 7), 1);
test.equal(kBucket._determineBucket(new Buffer("41", "hex"), 7), 1);
test.done();

@@ -58,3 +58,3 @@ };

var kBucket = new KBucket();
test.equal(kBucket.determineBucket(new Buffer("4100", "hex"), 7), 1);
test.equal(kBucket._determineBucket(new Buffer("4100", "hex"), 7), 1);
test.done();

@@ -66,4 +66,4 @@ };

var kBucket = new KBucket();
test.equal(kBucket.determineBucket(new Buffer("004100", "hex"), 15), 1);
test.equal(kBucket._determineBucket(new Buffer("004100", "hex"), 15), 1);
test.done();
};
};

@@ -45,2 +45,2 @@ "use strict";

test.done();
};
};

@@ -8,2 +8,11 @@ "use strict";

test['throws TypeError if id is not a Buffer'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.throws(function () {
kBucket.get("foo");
}, TypeError);
test.done();
};
test['get retrieves null if no contacts'] = function (test) {

@@ -54,2 +63,2 @@ test.expect(1);

test.done();
};
};

@@ -12,3 +12,3 @@ "use strict";

kBucket.add({id: new Buffer("a")});
test.equal(kBucket.indexOf({id: new Buffer("a")}), 0);
test.equal(kBucket._indexOf(new Buffer("a")), 0);
test.done();

@@ -21,4 +21,4 @@ };

kBucket.add({id: new Buffer("a")});
test.equal(kBucket.indexOf({id: new Buffer("b")}), -1);
test.equal(kBucket._indexOf(new Buffer("b")), -1);
test.done();
};
};

@@ -7,2 +7,12 @@ "use strict";

test['throws TypeError if contact.id is not a Buffer'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: "foo"};
test.throws(function () {
kBucket.remove(contact.id);
}, TypeError);
test.done();
};
test['removing a contact should remove contact from nested buckets'] = function (test) {

@@ -23,6 +33,18 @@ test.expect(2);

var contactToDelete = {id: new Buffer('8000', 'hex')};
test.equal(kBucket.high.indexOf(contactToDelete), 0);
kBucket.remove({id: new Buffer('8000', 'hex')});
test.equal(kBucket.high.indexOf(contactToDelete), -1);
test.equal(kBucket.high._indexOf(contactToDelete.id), 0);
kBucket.remove(new Buffer('8000', 'hex'));
test.equal(kBucket.high._indexOf(contactToDelete.id), -1);
test.done();
};
};
test['should generate "removed"'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: new Buffer("a")};
kBucket.on('removed', function (removedContact) {
test.deepEqual(removedContact, contact);
});
kBucket.add(contact);
kBucket.remove(contact.id);
test.done();
};

@@ -14,3 +14,3 @@ "use strict";

try {
kBucket.update(contact, 1);
kBucket._update(contact, 1);
} catch (exception) {

@@ -27,3 +27,3 @@ test.ok(true);

kBucket.add(contact);
kBucket.update({id: new Buffer("a"), vectorClock: 2}, 0);
kBucket._update({id: new Buffer("a"), vectorClock: 2}, 0);
test.equal(kBucket.bucket[0].vectorClock, 3);

@@ -39,3 +39,3 @@ test.done();

kBucket.add({id: new Buffer("b")});
kBucket.update(contact, 0);
kBucket._update(contact, 0);
test.equal(kBucket.bucket[1], contact);

@@ -52,3 +52,3 @@ test.done();

kBucket.add({id: new Buffer("b")});
kBucket.update({id: new Buffer("a"), newer: 'property', vectorClock: 4}, 0);
kBucket._update({id: new Buffer("a"), newer: 'property', vectorClock: 4}, 0);
test.ok(bufferEqual(kBucket.bucket[1].id, contact.id));

@@ -59,2 +59,16 @@ test.equal(kBucket.bucket[1].vectorClock, 4);

test.done();
};
};
test['should generate "updated"'] = function (test) {
test.expect(2);
var kBucket = new KBucket();
var contact1 = {id: new Buffer("a"), vectorClock: 1};
var contact2 = {id: new Buffer("a"), vectorClock: 2};
kBucket.on('updated', function (oldContact, newContact) {
test.deepEqual(oldContact, contact1);
test.deepEqual(newContact, contact2);
})
kBucket.add(contact1);
kBucket.add(contact2);
test.done();
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc