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 3.0.0 to 3.0.1

20

benchmarks/distance.js

@@ -1,14 +0,12 @@

"use strict";
'use strict'
var KBucket = require('../index')
var KBucket = require("../index.js");
var _0000000100100100 = new Buffer('0124', 'hex')
var _0100000000100100 = new Buffer('4024', 'hex')
var _0000000100100100 = new Buffer("0124", "hex");
var _0100000000100100 = new Buffer("4024", "hex");
var hrtime = process.hrtime();
for (var i = 0; i < 1e7; i++)
{
KBucket.distance(_0000000100100100, _0100000000100100);
var hrtime = process.hrtime()
for (var i = 0; i < 1e7; i++) {
KBucket.distance(_0000000100100100, _0100000000100100)
}
var diff = process.hrtime(hrtime);
console.log(diff[0] * 1e9 + diff[1]);
var diff = process.hrtime(hrtime)
console.log(diff[0] * 1e9 + diff[1])
/*
index.js - Kademlia DHT K-bucket implementation as a binary tree.

@@ -29,11 +28,12 @@

OTHER DEALINGS IN THE SOFTWARE.
*/
"use strict";
'use strict'
var bufferEquals = require('buffer-equals');
var EventEmitter = require('events').EventEmitter;
var inherits = require('inherits');
var randomBytes = require('randombytes');
var bufferEquals = require('buffer-equals')
var randomBytes = require('randombytes')
var EventEmitter = require('events').EventEmitter
var inherits = require('inherits')
module.exports = KBucket
/*

@@ -59,46 +59,36 @@ * `options`:

*/
var KBucket = module.exports = function KBucket (options) {
var self = this;
EventEmitter.call(self);
options = options || {};
function KBucket (options) {
EventEmitter.call(this)
options = options || {}
// use an arbiter from options or vectorClock arbiter by default
self.arbiter = options.arbiter || function arbiter(incumbent, candidate) {
if (incumbent.vectorClock > candidate.vectorClock) {
return incumbent;
}
return candidate;
};
// use an arbiter from options or vectorClock arbiter by default
this.arbiter = options.arbiter || function arbiter (incumbent, candidate) {
return incumbent.vectorClock > candidate.vectorClock ? incumbent : candidate
}
// the bucket array has least-recently-contacted at the "front/left" side
// and the most-recently-contaced at the "back/right" side
self.bucket = [];
self.localNodeId = options.localNodeId || randomBytes(20);
if (!Buffer.isBuffer(self.localNodeId)) {
throw new TypeError("localNodeId is not a Buffer");
}
self.numberOfNodesPerKBucket = options.numberOfNodesPerKBucket || 20;
self.numberOfNodesToPing = options.numberOfNodesToPing || 3;
self.root = options.root || self;
// the bucket array has least-recently-contacted at the "front/left" side
// and the most-recently-contaced at the "back/right" side
this.bucket = []
this.localNodeId = options.localNodeId || randomBytes(20)
if (!Buffer.isBuffer(this.localNodeId)) throw new TypeError('localNodeId is not a Buffer')
this.numberOfNodesPerKBucket = options.numberOfNodesPerKBucket || 20
this.numberOfNodesToPing = options.numberOfNodesToPing || 3
this.root = options.root || this
// V8 hints
self.dontSplit = null;
self.low = null;
self.high = null;
};
// V8 hints
this.dontSplit = null
this.low = null
this.high = null
}
inherits(KBucket, EventEmitter);
inherits(KBucket, EventEmitter)
KBucket.distance = function distance (firstId, secondId) {
var distance = 0;
var min = Math.min(firstId.length, secondId.length);
var max = Math.max(firstId.length, secondId.length);
for (var i = 0; i < min; ++i) {
distance = distance * 256 + (firstId[i] ^ secondId[i]);
}
for (; i < max; ++i) {
distance = distance * 256 + 255;
}
return distance;
};
KBucket.distance = function (firstId, secondId) {
var distance = 0
var min = Math.min(firstId.length, secondId.length)
var max = Math.max(firstId.length, secondId.length)
for (var i = 0; i < min; ++i) distance = distance * 256 + (firstId[i] ^ secondId[i])
for (; i < max; ++i) distance = distance * 256 + 255
return distance
}

@@ -109,50 +99,46 @@ // contact: *required* the contact object to add

KBucket.prototype._add = function (contact, bitIndex) {
var self = this;
// first check whether we are an inner node or a leaf (with bucket contents)
if (!self.bucket) {
// this is not a leaf node but an inner node with 'low' and 'high'
// branches; we will check the appropriate bit of the identifier and
// delegate to the appropriate node for further processing
if (self._determineBucket(contact.id, bitIndex++) < 0) {
return self.low._add(contact, bitIndex);
} else {
return self.high._add(contact, bitIndex);
}
// first check whether we are an inner node or a leaf (with bucket contents)
if (this.bucket === null) {
// this is not a leaf node but an inner node with 'low' and 'high'
// branches; we will check the appropriate bit of the identifier and
// delegate to the appropriate node for further processing
if (this._determineBucket(contact.id, bitIndex++) < 0) {
return this.low._add(contact, bitIndex)
} else {
return this.high._add(contact, bitIndex)
}
}
// check if the contact already exists
var index = self._indexOf(contact.id);
if (index >= 0) {
self._update(contact, index);
return self;
}
// check if the contact already exists
var index = this._indexOf(contact.id)
if (index >= 0) {
this._update(contact, index)
return this
}
if (self.bucket.length < self.numberOfNodesPerKBucket) {
self.bucket.push(contact);
self.emit('added', contact);
return self;
}
if (this.bucket.length < this.numberOfNodesPerKBucket) {
this.bucket.push(contact)
this.root.emit('added', contact)
return this
}
// the bucket is full
if (self.dontSplit) {
// we are not allowed to split the bucket
// we need to ping the first self.numberOfNodesToPing
// in order to determine if they are alive
// only if one of the pinged nodes does not respond, can the new contact
// be added (this prevents DoS flodding with new invalid contacts)
self.root.emit('ping', self.bucket.slice(0, self.numberOfNodesToPing), contact);
return self;
}
// the bucket is full
if (this.dontSplit) {
// we are not allowed to split the bucket
// we need to ping the first this.numberOfNodesToPing
// in order to determine if they are alive
// only if one of the pinged nodes does not respond, can the new contact
// be added (this prevents DoS flodding with new invalid contacts)
this.root.emit('ping', this.bucket.slice(0, this.numberOfNodesToPing), contact)
return this
}
return self._splitAndAdd(contact, bitIndex);
};
return this._splitAndAdd(contact, bitIndex)
}
// 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);
};
KBucket.prototype.add = function (contact) {
if (!Buffer.isBuffer(contact.id)) throw new TypeError('contact.id is not a Buffer')
return this._add(contact, 0)
}

@@ -164,31 +150,24 @@ // id: Buffer *required* node id

KBucket.prototype._closest = function (id, n, bitIndex) {
var self = this;
var contacts;
if (!self.bucket) {
if (self._determineBucket(id, bitIndex++) < 0) {
contacts = self.low._closest(id, n, bitIndex);
if (contacts.length < n) {
contacts = contacts.concat(self.high._closest(id, n, bitIndex));
}
} else {
contacts = self.high._closest(id, n, bitIndex);
if (contacts.length < n) {
contacts = contacts.concat(self.low._closest(id, n, bitIndex));
}
}
return contacts.slice(0, n);
if (this.bucket === null) {
var contacts
if (this._determineBucket(id, bitIndex++) < 0) {
contacts = this.low._closest(id, n, bitIndex)
if (contacts.length < n) contacts = contacts.concat(this.high._closest(id, n, bitIndex))
} else {
contacts = this.high._closest(id, n, bitIndex)
if (contacts.length < n) contacts = contacts.concat(this.low._closest(id, n, bitIndex))
}
contacts = self.bucket.slice();
contacts.forEach(function (storedContact) {
storedContact.distance = KBucket.distance(storedContact.id, id);
});
return contacts.slice(0, n)
}
contacts.sort(function (a, b) {return a.distance - b.distance;});
return this.bucket
.map(function (storedContact) {
storedContact.distance = KBucket.distance(storedContact.id, id)
return storedContact
})
.sort(function (a, b) { return a.distance - b.distance })
.slice(0, n)
}
return contacts.slice(0, n);
};
// id: Buffer *required* node id

@@ -198,7 +177,5 @@ // n: Integer *required* maximum number of closest contacts to return

KBucket.prototype.closest = function (id, n) {
if (!Buffer.isBuffer(id)) {
throw new TypeError("id is not a Buffer");
}
return this._closest(id, n, 0);
};
if (!Buffer.isBuffer(id)) throw new TypeError('id is not a Buffer')
return this._closest(id, n, 0)
}

@@ -209,11 +186,6 @@ // Counts the number of contacts recursively.

KBucket.prototype.count = function count () {
var self = this;
if (this.bucket !== null) return this.bucket.length
return this.high.count() + this.low.count()
}
if (self.bucket) {
return self.bucket.length;
} else {
return self.high.count() + self.low.count();
}
};
// Determines whether the id at the bitIndex is 0 or 1. If 0, returns -1, else 1

@@ -223,38 +195,32 @@ // id: a Buffer to compare localNodeId with

KBucket.prototype._determineBucket = function (id, bitIndex) {
var self = this;
bitIndex = bitIndex || 0
bitIndex = bitIndex || 0;
// **NOTE** remember that id is a Buffer and has granularity of
// bytes (8 bits), whereas the bitIndex is the _bit_ index (not byte)
// **NOTE** remember that id is a Buffer and has granularity of
// bytes (8 bits), whereas the bitIndex is the _bit_ index (not byte)
// id's that are too short are put in low bucket (1 byte = 8 bits)
// parseInt(bitIndex / 8) finds how many bytes the bitIndex describes
// bitIndex % 8 checks if we have extra bits beyond byte multiples
// if number of bytes is <= no. of bytes described by bitIndex and there
// are extra bits to consider, this means id has less bits than what
// bitIndex describes, id therefore is too short, and will be put in low
// bucket
var bytesDescribedByBitIndex = parseInt(bitIndex / 8, 10)
var bitIndexWithinByte = bitIndex % 8
if ((id.length <= bytesDescribedByBitIndex) && (bitIndexWithinByte !== 0)) return -1
// id's that are too short are put in low bucket (1 byte = 8 bits)
// parseInt(bitIndex / 8) finds how many bytes the bitIndex describes
// bitIndex % 8 checks if we have extra bits beyond byte multiples
// if number of bytes is <= no. of bytes described by bitIndex and there
// are extra bits to consider, this means id has less bits than what
// bitIndex describes, id therefore is too short, and will be put in low
// bucket
var bytesDescribedByBitIndex = parseInt(bitIndex / 8, 10);
var bitIndexWithinByte = bitIndex % 8;
if ((id.length <= bytesDescribedByBitIndex)
&& (bitIndexWithinByte != 0))
return -1;
var byteUnderConsideration = id[bytesDescribedByBitIndex]
var byteUnderConsideration = id[bytesDescribedByBitIndex];
// byteUnderConsideration is an integer from 0 to 255 represented by 8 bits
// where 255 is 11111111 and 0 is 00000000
// in order to find out whether the bit at bitIndexWithinByte is set
// we construct Math.pow(2, (7 - bitIndexWithinByte)) which will consist
// of all bits being 0, with only one bit set to 1
// for example, if bitIndexWithinByte is 3, we will construct 00010000 by
// Math.pow(2, (7 - 3)) -> Math.pow(2, 4) -> 16
if (byteUnderConsideration & Math.pow(2, (7 - bitIndexWithinByte))) return 1
// byteUnderConsideration is an integer from 0 to 255 represented by 8 bits
// where 255 is 11111111 and 0 is 00000000
// in order to find out whether the bit at bitIndexWithinByte is set
// we construct Math.pow(2, (7 - bitIndexWithinByte)) which will consist
// of all bits being 0, with only one bit set to 1
// for example, if bitIndexWithinByte is 3, we will construct 00010000 by
// Math.pow(2, (7 - 3)) -> Math.pow(2, 4) -> 16
if (byteUnderConsideration & Math.pow(2, (7 - bitIndexWithinByte))) {
return 1;
}
return -1
}
return -1;
};
// Get a contact by its exact ID.

@@ -268,19 +234,15 @@ // If this is a leaf, loop through the bucket contents and return the correct

KBucket.prototype._get = function (id, bitIndex) {
var self = this;
if (!self.bucket) {
if (self._determineBucket(id, bitIndex++) < 0) {
return self.low._get(id, bitIndex);
} else {
return self.high._get(id, bitIndex);
}
if (this.bucket === null) {
if (this._determineBucket(id, bitIndex++) < 0) {
return this.low._get(id, bitIndex)
} else {
return this.high._get(id, bitIndex)
}
}
var index = self._indexOf(id); // index of uses contact id for matching
if (index < 0) {
return null; // contact not found
}
var index = this._indexOf(id) // index of uses contact id for matching
if (index < 0) return null // contact not found
return self.bucket[index];
};
return this.bucket[index]
}

@@ -293,17 +255,16 @@ // Get a contact by its exact ID.

KBucket.prototype.get = function get (id) {
if (!Buffer.isBuffer(id)) {
throw new TypeError("id is not a Buffer");
}
return this._get(id, 0);
};
if (!Buffer.isBuffer(id)) throw new TypeError('id is not a Buffer')
return this._get(id, 0)
}
// id: Buffer Contact node id.
// 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 (bufferEquals(self.bucket[i].id, id)) return i;
}
return -1;
};
for (var i = 0; i < this.bucket.length; i++) {
if (bufferEquals(this.bucket[i].id, id)) return i
}
return -1
}
// id: Buffer *required* The ID of the contact to remove.

@@ -313,35 +274,32 @@ // bitIndex: the bitIndex to which bit to check in the Buffer for navigating

KBucket.prototype._remove = function (id, bitIndex) {
var self = this;
// first check whether we are an inner node or a leaf (with bucket contents)
if (!self.bucket) {
// this is not a leaf node but an inner node with 'low' and 'high'
// branches; we will check the appropriate bit of the identifier and
// delegate to the appropriate node for further processing
if (self._determineBucket(id, bitIndex++) < 0) {
return self.low._remove(id, bitIndex);
} else {
return self.high._remove(id, bitIndex);
}
// first check whether we are an inner node or a leaf (with bucket contents)
if (this.bucket === null) {
// this is not a leaf node but an inner node with 'low' and 'high'
// branches; we will check the appropriate bit of the identifier and
// delegate to the appropriate node for further processing
if (this._determineBucket(id, bitIndex++) < 0) {
return this.low._remove(id, bitIndex)
} else {
return this.high._remove(id, bitIndex)
}
}
var index = self._indexOf(id);
if (index >= 0) {
var contact = self.bucket.splice(index, 1)[0];
self.emit('removed', contact);
}
return self;
};
var index = this._indexOf(id)
if (index >= 0) {
var contact = this.bucket.splice(index, 1)[0]
this.root.emit('removed', contact)
}
return this
}
// 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);
};
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
// bucket that was split as an inner node of the binary tree of buckets by
// setting self.bucket = undefined;
// setting this.bucket = null
// contact: *required* the contact object to add

@@ -351,62 +309,55 @@ // bitIndex: the bitIndex to which byte to check in the Buffer for navigating the

KBucket.prototype._splitAndAdd = function (contact, bitIndex) {
var self = this;
self.low = new KBucket({
arbiter: self.arbiter,
localNodeId: self.localNodeId,
numberOfNodesPerKBucket: self.numberOfNodesPerKBucket,
numberOfNodesToPing: self.numberOfNodesToPing,
root: self.root
});
self.high = new KBucket({
arbiter: self.arbiter,
localNodeId: self.localNodeId,
numberOfNodesPerKBucket: self.numberOfNodesPerKBucket,
numberOfNodesToPing: self.numberOfNodesToPing,
root: self.root
});
this.low = new KBucket({
arbiter: this.arbiter,
localNodeId: this.localNodeId,
numberOfNodesPerKBucket: this.numberOfNodesPerKBucket,
numberOfNodesToPing: this.numberOfNodesToPing,
root: this.root
})
this.high = new KBucket({
arbiter: this.arbiter,
localNodeId: this.localNodeId,
numberOfNodesPerKBucket: this.numberOfNodesPerKBucket,
numberOfNodesToPing: this.numberOfNodesToPing,
root: this.root
})
bitIndex = bitIndex || 0;
bitIndex = bitIndex || 0
// redistribute existing contacts amongst the two newly created buckets
self.bucket.forEach(function (storedContact) {
if (self._determineBucket(storedContact.id, bitIndex) < 0) {
self.low.add(storedContact);
} else {
self.high.add(storedContact);
}
});
self.bucket = undefined; // mark as inner tree node
// don't split the "far away" bucket
// we check where the local node would end up and mark the other one as
// "dontSplit" (i.e. "far away")
if (self._determineBucket(self.localNodeId, bitIndex) < 0) {
// local node belongs to "low" bucket, so mark the other one
self.high.dontSplit = true;
// redistribute existing contacts amongst the two newly created buckets
this.bucket.forEach(function (storedContact) {
if (this._determineBucket(storedContact.id, bitIndex) < 0) {
this.low.add(storedContact)
} else {
self.low.dontSplit = true;
this.high.add(storedContact)
}
}.bind(this))
// add the contact being added
self._add(contact, bitIndex);
this.bucket = null // mark as inner tree node
return self;
};
// don't split the "far away" bucket
// we check where the local node would end up and mark the other one as
// "dontSplit" (i.e. "far away")
if (this._determineBucket(this.localNodeId, bitIndex) < 0) {
// local node belongs to "low" bucket, so mark the other one
this.high.dontSplit = true
} else {
this.low.dontSplit = true
}
// add the contact being added
this._add(contact, bitIndex)
return this
}
// Returns all the contacts contained in the tree as an array.
// If self is a leaf, return a copy of the bucket. `slice` is used so that we
// If this is a leaf, return a copy of the bucket. `slice` is used so that we
// don't accidentally leak an internal reference out that might be accidentally
// misused. If self is not a leaf, return the union of the low and high
// misused. If this is not a leaf, return the union of the low and high
// branches (themselves also as arrays).
KBucket.prototype.toArray = function toArray () {
var self = this;
KBucket.prototype.toArray = function () {
if (this.bucket !== null) return this.bucket.slice(0)
return this.low.toArray().concat(this.high.toArray())
}
if (self.bucket) {
return self.bucket.slice(0);
} else {
return self.low.toArray().concat(self.high.toArray());
}
};
// Updates the contact selected by the arbiter.

@@ -424,19 +375,16 @@ // If the selection is our old contact and the candidate is some new contact

KBucket.prototype._update = function (contact, index) {
var self = this;
// sanity check
if (!bufferEquals(self.bucket[index].id, contact.id)) {
throw new Error("indexOf() calculation resulted in wrong index")
}
// sanity check
if (!bufferEquals(this.bucket[index].id, contact.id)) {
throw new Error('indexOf() calculation resulted in wrong index')
}
var incumbent = self.bucket[index];
var selection = self.arbiter(incumbent, contact);
if (selection === incumbent && incumbent !== contact) {
// if the selection is our old contact and the candidate is some new
// contact, then there is nothing to do
return;
}
var incumbent = this.bucket[index]
var selection = this.arbiter(incumbent, contact)
// if the selection is our old contact and the candidate is some new
// contact, then there is nothing to do
if (selection === incumbent && incumbent !== contact) return
self.bucket.splice(index, 1); // remove old contact
self.bucket.push(selection); // add more recent contact version
self.emit('updated', incumbent, selection);
};
this.bucket.splice(index, 1) // remove old contact
this.bucket.push(selection) // add more recent contact version
this.root.emit('updated', incumbent, selection)
}
{
"name": "k-bucket",
"version": "3.0.0",
"version": "3.0.1",
"description": "Kademlia DHT K-bucket implementation as a binary tree",
"scripts": {
"distance-benchmark": "node benchmarks/distance.js",
"test": "node scripts/test.js"
},
"main": "index.js",
"devDependencies": {
"nodeunit": "0.9.x"
},
"dependencies": {
"buffer-equals": "^1.0.3",
"inherits": "^2.0.1",
"randombytes": "^2.0.3"
},
"repository": {
"type": "git",
"url": "git@github.com:tristanls/k-bucket.git"
},
"keywords": [

@@ -27,2 +10,6 @@ "k-bucket",

],
"bugs": {
"url": "https://github.com/tristanls/k-bucket/issues"
},
"license": "MIT",
"contributors": [

@@ -37,3 +24,22 @@ "Tristan Slominski <tristan.slominski@gmail.com>",

],
"license": "MIT"
"main": "./index.js",
"repository": {
"type": "git",
"url": "git@github.com:tristanls/k-bucket.git"
},
"scripts": {
"benchmark:distance": "node benchmarks/distance.js",
"lint": "standard",
"test": "npm run lint && npm run unit",
"unit": "node scripts/test.js"
},
"dependencies": {
"buffer-equals": "^1.0.3",
"inherits": "^2.0.1",
"randombytes": "^2.0.3"
},
"devDependencies": {
"nodeunit": "0.9.x",
"standard": "^7.0.1"
}
}

@@ -191,15 +191,11 @@ # k-bucket

#### kBucket._indexOf(contact)
#### kBucket._indexOf(id)
_**CAUTION: reserved for internal use**_
* `contact`: _Object_ The contact object.
* `id`: _Buffer_ Contact node id.
* Any satellite data that is part of the `contact` object will not be altered, only `id` is used.
* Return: _Integer_ Index of `contact` if it exists, -1 otherwise.
* `id`: _Buffer_ Contact node id.
* Return: _Integer_ Index of `contact` with provided `id` if it exists, -1 otherwise.
Returns the index of the `contact` if it exists, returns -1 otherwise.
Returns the index of the `contact` with provided `id` if it exists, returns -1 otherwise.
_NOTE: `kBucket._indexOf(contact)` does not use `arbiter` in the comparison.
#### kBucket._splitAndAdd(contact, [bitIndex])

@@ -206,0 +202,0 @@

#!/usr/bin/env node
var reporter = require('nodeunit').reporters.default;
reporter.run(['test']);
var reporter = require('nodeunit').reporters.default
reporter.run(['test'])

@@ -1,90 +0,95 @@

"use strict";
'use strict'
var KBucket = require('../index')
var KBucket = require('../index.js');
var test = module.exports = {}
var test = module.exports = {};
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.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) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: new Buffer("a")};
kBucket.add(contact);
test.ok(kBucket.bucket[0] === contact);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
var contact = { id: new Buffer('a') }
kBucket.add(contact)
test.ok(kBucket.bucket[0] === contact)
test.done()
}
test['adding an existing contact does not increase number of contacts in ' +
'bucket' ] = function (test) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: new Buffer("a")};
kBucket.add(contact);
kBucket.add({id: new Buffer("a")});
test.equal(kBucket.bucket.length, 1);
test.done();
};
test['adding an existing contact does not increase number of contacts in bucket'] = function (test) {
test.expect(1)
var kBucket = new KBucket()
var contact = { id: new Buffer('a') }
kBucket.add(contact)
kBucket.add({id: new Buffer('a')})
test.equal(kBucket.bucket.length, 1)
test.done()
}
test['adding same contact moves it to the end of the bucket ' +
'(most-recently-contacted end)'] = function (test) {
test.expect(5);
var kBucket = new KBucket();
var contact = {id: new Buffer("a")};
kBucket.add(contact);
test.equal(kBucket.bucket.length, 1);
kBucket.add({id: new Buffer("b")});
test.equal(kBucket.bucket.length, 2);
test.equal(kBucket.bucket[0], contact); // least-recently-contacted end
kBucket.add(contact);
test.equal(kBucket.bucket.length, 2);
test.equal(kBucket.bucket[1], contact); // most-recently-contacted end
test.done();
};
test['adding same contact moves it to the end of the bucket (most-recently-contacted end)'] = function (test) {
test.expect(5)
var kBucket = new KBucket()
var contact = { id: new Buffer('a') }
kBucket.add(contact)
test.equal(kBucket.bucket.length, 1)
kBucket.add({ id: new Buffer('b') })
test.equal(kBucket.bucket.length, 2)
test.equal(kBucket.bucket[0], contact) // least-recently-contacted end
kBucket.add(contact)
test.equal(kBucket.bucket.length, 2)
test.equal(kBucket.bucket[1], contact) // most-recently-contacted end
test.done()
}
test['adding contact to bucket that can\'t be split results in calling' +
' "ping" callback'] = function (test) {
var i, iString, j;
test.expect(3 /*numberOfNodesToPing*/ + 2);
var kBucket = new KBucket({
localNodeId: new Buffer('0000', 'hex')
});
kBucket.on('ping', function (contacts, replacement) {
test.equal(contacts.length, kBucket.numberOfNodesToPing);
// console.dir(kBucket.high.bucket[0]);
for (var i = 0; i < kBucket.numberOfNodesToPing; i++) {
// the least recently contacted end of the bucket should be pinged
test.equal(contacts[i], kBucket.high.bucket[i]);
}
test.deepEqual(replacement, {id: new Buffer(iString, 'hex')})
test.done();
})
for (var j = 0; j < kBucket.numberOfNodesPerKBucket + 1; j++) {
iString = j.toString('16');
if (iString.length < 2) {
iString = '0' + iString;
}
iString = '80' + iString; // make sure all go into "far away" bucket
kBucket.add({id: new Buffer(iString, 'hex')});
test['adding contact to bucket that can\'t be split results in calling "ping" callback'] = function (test) {
test.expect(3 /* numberOfNodesToPing*/ + 2)
var kBucket = new KBucket({ localNodeId: new Buffer([ 0x00, 0x00 ]) })
kBucket.on('ping', function (contacts, replacement) {
test.equal(contacts.length, kBucket.numberOfNodesToPing)
// console.dir(kBucket.high.bucket[0])
for (var i = 0; i < kBucket.numberOfNodesToPing; ++i) {
// the least recently contacted end of the bucket should be pinged
test.equal(contacts[i], kBucket.high.bucket[i])
}
};
test.deepEqual(replacement, { id: new Buffer([ 0x80, j ]) })
test.done()
})
for (var j = 0; j < kBucket.numberOfNodesPerKBucket + 1; ++j) {
kBucket.add({ id: new Buffer([ 0x80, j ]) }) // make sure all go into "far away" bucket
}
}
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();
};
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()
}
test['should generate event "added" when adding to a split bucket'] = function (test) {
test.expect(2)
var kBucket = new KBucket({
localNodeId: new Buffer('') // need non-random localNodeId for deterministic splits
})
for (var i = 0; i < kBucket.numberOfNodesPerKBucket + 1; ++i) {
kBucket.add({ id: new Buffer('' + i) })
}
test.ok(!kBucket.bucket)
var contact = { id: new Buffer('a') }
kBucket.on('added', function (newContact) {
test.deepEqual(newContact, contact)
})
kBucket.add(contact)
test.done()
}

@@ -1,116 +0,74 @@

"use strict";
'use strict'
var KBucket = require('../index')
var KBucket = require('../index.js');
var test = module.exports = {}
var test = module.exports = {};
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.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) {
test.expect(3);
var kBucket = new KBucket();
kBucket.add({id: new Buffer('00', 'hex')}); // 00000000
kBucket.add({id: new Buffer('01', 'hex')}); // 00000001
kBucket.add({id: new Buffer('02', 'hex')}); // 00000010
kBucket.add({id: new Buffer('03', 'hex')}); // 00000011
kBucket.add({id: new Buffer('04', 'hex')}); // 00000100
kBucket.add({id: new Buffer('05', 'hex')}); // 00000101
kBucket.add({id: new Buffer('06', 'hex')}); // 00000110
kBucket.add({id: new Buffer('07', 'hex')}); // 00000111
kBucket.add({id: new Buffer('08', 'hex')}); // 00001000
kBucket.add({id: new Buffer('09', 'hex')}); // 00001001
kBucket.add({id: new Buffer('0a', 'hex')}); // 00001010
kBucket.add({id: new Buffer('0b', 'hex')}); // 00001011
kBucket.add({id: new Buffer('0c', 'hex')}); // 00001100
kBucket.add({id: new Buffer('0d', 'hex')}); // 00001101
kBucket.add({id: new Buffer('0e', 'hex')}); // 00001110
kBucket.add({id: new Buffer('0f', 'hex')}); // 00001111
kBucket.add({id: new Buffer('10', 'hex')}); // 00010000
kBucket.add({id: new Buffer('11', 'hex')}); // 00010001
var contact = {id: new Buffer('15', 'hex')};// 00010101
var contacts = kBucket.closest(contact.id, 3);
test.deepEqual(contacts[0].id, new Buffer('11', 'hex')); // distance: 00000100
test.deepEqual(contacts[1].id, new Buffer('10', 'hex')); // distance: 00000101
test.deepEqual(contacts[2].id, new Buffer('05', 'hex')); // distance: 00010000
test.done();
};
test.expect(3)
var kBucket = new KBucket()
for (var i = 0; i < 0x12; ++i) kBucket.add({ id: new Buffer([ i ]) })
var contact = { id: new Buffer([ 0x15 ]) } // 00010101
var contacts = kBucket.closest(contact.id, 3)
test.deepEqual(contacts[0].id, new Buffer([ 0x11 ])) // distance: 00000100
test.deepEqual(contacts[1].id, new Buffer([ 0x10 ])) // distance: 00000101
test.deepEqual(contacts[2].id, new Buffer([ 0x05 ])) // distance: 00010000
test.done()
}
test['closest nodes are returned (including exact match)'] = function (test) {
test.expect(3);
var kBucket = new KBucket();
kBucket.add({id: new Buffer('00', 'hex')}); // 00000000
kBucket.add({id: new Buffer('01', 'hex')}); // 00000001
kBucket.add({id: new Buffer('02', 'hex')}); // 00000010
kBucket.add({id: new Buffer('03', 'hex')}); // 00000011
kBucket.add({id: new Buffer('04', 'hex')}); // 00000100
kBucket.add({id: new Buffer('05', 'hex')}); // 00000101
kBucket.add({id: new Buffer('06', 'hex')}); // 00000110
kBucket.add({id: new Buffer('07', 'hex')}); // 00000111
kBucket.add({id: new Buffer('08', 'hex')}); // 00001000
kBucket.add({id: new Buffer('09', 'hex')}); // 00001001
kBucket.add({id: new Buffer('0a', 'hex')}); // 00001010
kBucket.add({id: new Buffer('0b', 'hex')}); // 00001011
kBucket.add({id: new Buffer('0c', 'hex')}); // 00001100
kBucket.add({id: new Buffer('0d', 'hex')}); // 00001101
kBucket.add({id: new Buffer('0e', 'hex')}); // 00001110
kBucket.add({id: new Buffer('0f', 'hex')}); // 00001111
kBucket.add({id: new Buffer('10', 'hex')}); // 00010000
kBucket.add({id: new Buffer('11', 'hex')}); // 00010001
var contact = {id: new Buffer('11', 'hex')};// 00010001
var contacts = kBucket.closest(contact.id, 3);
test.deepEqual(contacts[0].id, new Buffer('11', 'hex')); // distance: 00000000
test.deepEqual(contacts[1].id, new Buffer('10', 'hex')); // distance: 00000001
test.deepEqual(contacts[2].id, new Buffer('01', 'hex')); // distance: 00010000
test.done();
};
test.expect(3)
var kBucket = new KBucket()
for (var i = 0; i < 0x12; ++i) kBucket.add({ id: new Buffer([ i ]) })
var contact = {id: new Buffer([ 0x11 ])} // 00010001
var contacts = kBucket.closest(contact.id, 3)
test.deepEqual(contacts[0].id, new Buffer([ 0x11 ])) // distance: 00000000
test.deepEqual(contacts[1].id, new Buffer([ 0x10 ])) // distance: 00000001
test.deepEqual(contacts[2].id, new Buffer([ 0x01 ])) // distance: 00010000
test.done()
}
test['closest nodes are returned even if there isn\'t enough in one bucket'] = function (test) {
test.expect(22);
var i, iString;
var kBucket = new KBucket({localNodeId: new Buffer('0000', 'hex')});
for (i = 0; i < kBucket.numberOfNodesPerKBucket; i++) {
iString = i.toString('16');
if (iString.length < 2) {
iString = '0' + iString;
}
var farString = '80' + iString; // make sure all go into "far away" bucket
kBucket.add({id: new Buffer(farString, 'hex')});
var nearString = '01' + iString;
kBucket.add({id: new Buffer(nearString, 'hex')});
}
kBucket.add({id: new Buffer('0001', 'hex')});
var contact = {id: new Buffer('0003', 'hex')}; // 0000000000000011
var contacts = kBucket.closest(contact.id, 22);
test.deepEqual(contacts[0].id, new Buffer('0001', 'hex')); // distance: 0000000000000010
test.deepEqual(contacts[1].id, new Buffer('0103', 'hex')); // distance: 0000000100000000
test.deepEqual(contacts[2].id, new Buffer('0102', 'hex')); // distance: 0000000100000010
test.deepEqual(contacts[3].id, new Buffer('0101', 'hex'));
test.deepEqual(contacts[4].id, new Buffer('0100', 'hex'));
test.deepEqual(contacts[5].id, new Buffer('0107', 'hex'));
test.deepEqual(contacts[6].id, new Buffer('0106', 'hex'));
test.deepEqual(contacts[7].id, new Buffer('0105', 'hex'));
test.deepEqual(contacts[8].id, new Buffer('0104', 'hex'));
test.deepEqual(contacts[9].id, new Buffer('010b', 'hex'));
test.deepEqual(contacts[10].id, new Buffer('010a', 'hex'));
test.deepEqual(contacts[11].id, new Buffer('0109', 'hex'));
test.deepEqual(contacts[12].id, new Buffer('0108', 'hex'));
test.deepEqual(contacts[13].id, new Buffer('010f', 'hex'));
test.deepEqual(contacts[14].id, new Buffer('010e', 'hex'));
test.deepEqual(contacts[15].id, new Buffer('010d', 'hex'));
test.deepEqual(contacts[16].id, new Buffer('010c', 'hex'));
test.deepEqual(contacts[17].id, new Buffer('0113', 'hex'));
test.deepEqual(contacts[18].id, new Buffer('0112', 'hex'));
test.deepEqual(contacts[19].id, new Buffer('0111', 'hex'));
test.deepEqual(contacts[20].id, new Buffer('0110', 'hex'));
test.deepEqual(contacts[21].id, new Buffer('8003', 'hex')); // distance: 1000000000000000
// console.log(require('util').inspect(kBucket, false, null));
test.done();
};
test["closest nodes are returned even if there isn't enough in one bucket"] = function (test) {
test.expect(22)
var kBucket = new KBucket({ localNodeId: new Buffer([ 0x00, 0x00 ]) })
for (var i = 0; i < kBucket.numberOfNodesPerKBucket; i++) {
kBucket.add({ id: new Buffer([ 0x80, i ]) })
kBucket.add({ id: new Buffer([ 0x01, i ]) })
}
kBucket.add({ id: new Buffer([ 0x00, 0x01 ]) })
var contact = { id: new Buffer([ 0x00, 0x03 ]) } // 0000000000000011
var contacts = kBucket.closest(contact.id, 22)
test.deepEqual(contacts[0].id, new Buffer([ 0x00, 0x01 ])) // distance: 0000000000000010
test.deepEqual(contacts[1].id, new Buffer([ 0x01, 0x03 ])) // distance: 0000000100000000
test.deepEqual(contacts[2].id, new Buffer([ 0x01, 0x02 ])) // distance: 0000000100000010
test.deepEqual(contacts[3].id, new Buffer([ 0x01, 0x01 ]))
test.deepEqual(contacts[4].id, new Buffer([ 0x01, 0x00 ]))
test.deepEqual(contacts[5].id, new Buffer([ 0x01, 0x07 ]))
test.deepEqual(contacts[6].id, new Buffer([ 0x01, 0x06 ]))
test.deepEqual(contacts[7].id, new Buffer([ 0x01, 0x05 ]))
test.deepEqual(contacts[8].id, new Buffer([ 0x01, 0x04 ]))
test.deepEqual(contacts[9].id, new Buffer([ 0x01, 0x0b ]))
test.deepEqual(contacts[10].id, new Buffer([ 0x01, 0x0a ]))
test.deepEqual(contacts[11].id, new Buffer([ 0x01, 0x09 ]))
test.deepEqual(contacts[12].id, new Buffer([ 0x01, 0x08 ]))
test.deepEqual(contacts[13].id, new Buffer([ 0x01, 0x0f ]))
test.deepEqual(contacts[14].id, new Buffer([ 0x01, 0x0e ]))
test.deepEqual(contacts[15].id, new Buffer([ 0x01, 0x0d ]))
test.deepEqual(contacts[16].id, new Buffer([ 0x01, 0x0c ]))
test.deepEqual(contacts[17].id, new Buffer([ 0x01, 0x13 ]))
test.deepEqual(contacts[18].id, new Buffer([ 0x01, 0x12 ]))
test.deepEqual(contacts[19].id, new Buffer([ 0x01, 0x11 ]))
test.deepEqual(contacts[20].id, new Buffer([ 0x01, 0x10 ]))
test.deepEqual(contacts[21].id, new Buffer([ 0x80, 0x03 ])) // distance: 1000000000000000
// console.log(require('util').inspect(kBucket, false, null))
test.done()
}

@@ -1,48 +0,47 @@

"use strict";
'use strict'
var KBucket = require('../index')
var KBucket = require('../index.js');
var test = module.exports = {}
var test = module.exports = {};
test['count returns 0 when no contacts in bucket'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.equal(kBucket.count(), 0);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
test.equal(kBucket.count(), 0)
test.done()
}
test['count returns 1 when 1 contact in bucket'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: new Buffer("a")};
kBucket.add(contact);
test.equal(kBucket.count(), 1);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
var contact = { id: new Buffer('a') }
kBucket.add(contact)
test.equal(kBucket.count(), 1)
test.done()
}
test['count returns 1 when same contact added to bucket twice'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: new Buffer("a")};
kBucket.add(contact);
kBucket.add(contact);
test.equal(kBucket.count(), 1);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
var contact = { id: new Buffer('a') }
kBucket.add(contact)
kBucket.add(contact)
test.equal(kBucket.count(), 1)
test.done()
}
test['count returns number of added unique contacts'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
kBucket.add({id: new Buffer("a")});
kBucket.add({id: new Buffer("a")});
kBucket.add({id: new Buffer("b")});
kBucket.add({id: new Buffer("b")});
kBucket.add({id: new Buffer("c")});
kBucket.add({id: new Buffer("d")});
kBucket.add({id: new Buffer("c")});
kBucket.add({id: new Buffer("d")});
kBucket.add({id: new Buffer("e")});
kBucket.add({id: new Buffer("f")});
test.equal(kBucket.count(), 6);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
kBucket.add({ id: new Buffer('a') })
kBucket.add({ id: new Buffer('a') })
kBucket.add({ id: new Buffer('b') })
kBucket.add({ id: new Buffer('b') })
kBucket.add({ id: new Buffer('c') })
kBucket.add({ id: new Buffer('d') })
kBucket.add({ id: new Buffer('c') })
kBucket.add({ id: new Buffer('d') })
kBucket.add({ id: new Buffer('e') })
kBucket.add({ id: new Buffer('f') })
test.equal(kBucket.count(), 6)
test.done()
}

@@ -1,48 +0,45 @@

"use strict";
'use strict'
var bufferEqual = require('buffer-equal')
var EventEmitter = require('events').EventEmitter
var KBucket = require('../index')
var bufferEqual = require('buffer-equal');
var EventEmitter = require('events').EventEmitter;
var test = module.exports = {}
var KBucket = require('../index.js');
var test = module.exports = {};
test['localNodeId should be a random SHA-1 if not provided'] = function (test) {
test.expect(2);
var kBucket = new KBucket();
test.ok(kBucket.localNodeId instanceof Buffer);
test.equal(kBucket.localNodeId.length, 20); // SHA-1 is 160 bits (20 bytes)
test.done();
};
test.expect(2)
var kBucket = new KBucket()
test.ok(kBucket.localNodeId instanceof Buffer)
test.equal(kBucket.localNodeId.length, 20) // SHA-1 is 160 bits (20 bytes)
test.done()
}
test['localNodeId is a Buffer populated from options if options.localNodeId Buffer is provided'] = function (test) {
var localNodeId = new Buffer("some length");
test.expect(2);
var kBucket = new KBucket({localNodeId: localNodeId});
test.ok(kBucket.localNodeId instanceof Buffer);
test.ok(bufferEqual(kBucket.localNodeId, localNodeId));
test.done();
};
var localNodeId = new Buffer('some length')
test.expect(2)
var kBucket = new KBucket({localNodeId: localNodeId})
test.ok(kBucket.localNodeId instanceof Buffer)
test.ok(bufferEqual(kBucket.localNodeId, localNodeId))
test.done()
}
test['throws exception if options.localNodeId is a String'] = function (test) {
var localNodeId = "some identifier";
test.expect(1);
test.throws(function() {
new KBucket({localNodeId: "some identifier"});
}, Error);
test.done();
};
test.expect(1)
test.throws(function () {
return new KBucket({ localNodeId: 'some identifier' })
}, Error)
test.done()
}
test['root is \'self\' if not provided'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.strictEqual(kBucket.root, kBucket);
test.done();
};
test["root is 'self' if not provided"] = function (test) {
test.expect(1)
var kBucket = new KBucket()
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();
};
test.expect(1)
var kBucket = new KBucket()
test.ok(kBucket instanceof EventEmitter)
test.done()
}

@@ -1,61 +0,60 @@

"use strict";
'use strict'
var KBucket = require('../index')
var KBucket = require('../index.js');
var test = module.exports = {}
var test = module.exports = {};
test['id 00000000, bitIndex 0, should be low'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.equal(kBucket._determineBucket(new Buffer("00", "hex"), 0), -1);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
test.equal(kBucket._determineBucket(new Buffer([ 0x00 ]), 0), -1)
test.done()
}
test['id 01000000, bitIndex 0, should be low'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.equal(kBucket._determineBucket(new Buffer("40", "hex"), 0), -1);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
test.equal(kBucket._determineBucket(new Buffer([ 0x40 ]), 0), -1)
test.done()
}
test['id 01000000, bitIndex 1, should be high'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.equal(kBucket._determineBucket(new Buffer("40", "hex"), 1), 1);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
test.equal(kBucket._determineBucket(new Buffer([ 0x40 ]), 1), 1)
test.done()
}
test['id 01000000, bitIndex 2, should be low'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.equal(kBucket._determineBucket(new Buffer("40", "hex"), 2), -1);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
test.equal(kBucket._determineBucket(new Buffer([ 0x40 ]), 2), -1)
test.done()
}
test['id 01000000, bitIndex 9, should be low'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.equal(kBucket._determineBucket(new Buffer("40", "hex"), 9), -1);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
test.equal(kBucket._determineBucket(new Buffer([ 0x40 ]), 9), -1)
test.done()
}
test['id 01000001, bitIndex 7, should be high'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.equal(kBucket._determineBucket(new Buffer("41", "hex"), 7), 1);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
test.equal(kBucket._determineBucket(new Buffer([ 0x41 ]), 7), 1)
test.done()
}
test['id 0100000100000000, bitIndex 7, should be high'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.equal(kBucket._determineBucket(new Buffer("4100", "hex"), 7), 1);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
test.equal(kBucket._determineBucket(new Buffer([ 0x41, 0x00 ]), 7), 1)
test.done()
}
test['id 000000000100000100000000, bitIndex 15, should be high'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.equal(kBucket._determineBucket(new Buffer("004100", "hex"), 15), 1);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
test.equal(kBucket._determineBucket(new Buffer([ 0x00, 0x41, 0x00 ]), 15), 1)
test.done()
}

@@ -1,45 +0,34 @@

"use strict";
'use strict'
var KBucket = require('../index')
var KBucket = require('../index.js');
var test = module.exports = {}
var test = module.exports = {};
test['distance between 00000000 and 00000000 is 00000000'] = function (test) {
test.expect(1);
test.equal(
KBucket.distance(new Buffer('00', 'hex'), new Buffer('00', 'hex')),
0);
test.done();
};
test.expect(1)
test.equal(KBucket.distance(new Buffer([ 0x00 ]), new Buffer([ 0x00 ])), 0)
test.done()
}
test['distance between 00000000 and 00000001 is 00000001'] = function (test) {
test.expect(1);
test.equal(
KBucket.distance(new Buffer('00', 'hex'), new Buffer('01', 'hex')),
1);
test.done();
};
test.expect(1)
test.equal(KBucket.distance(new Buffer([ 0x00 ]), new Buffer([ 0x01 ])), 1)
test.done()
}
test['distance between 00000010 and 00000001 is 00000011'] = function (test) {
test.expect(1);
test.equal(
KBucket.distance(new Buffer('02', 'hex'), new Buffer('01', 'hex')),
3);
test.done();
};
test.expect(1)
test.equal(KBucket.distance(new Buffer([ 0x02 ]), new Buffer([ 0x01 ])), 3)
test.done()
}
test['distance between 00000000 and 0000000000000000 is 0000000011111111'] = function (test) {
test.expect(1);
test.equal(
KBucket.distance(new Buffer('00', 'hex'), new Buffer('0000', 'hex')),
255);
test.done();
};
test.expect(1)
test.equal(KBucket.distance(new Buffer([ 0x00 ]), new Buffer([ 0x00, 0x00 ])), 255)
test.done()
}
test['distance between 0000000100100100 and 0100000000100100 is 0100000100000000'] = function (test) {
test.expect(1);
test.equal(
KBucket.distance(new Buffer('0124', 'hex'), new Buffer('4024', 'hex')),
16640);
test.done();
};
test.expect(1)
test.equal(KBucket.distance(new Buffer([ 0x01, 0x24 ]), new Buffer([ 0x40, 0x24 ])), 16640)
test.done()
}

@@ -1,62 +0,55 @@

"use strict";
'use strict'
var bufferEqual = require('buffer-equal')
var KBucket = require('../index')
var bufferEqual = require('buffer-equal');
var KBucket = require('../index.js');
var test = module.exports = {}
var test = module.exports = {};
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.expect(1)
var kBucket = new KBucket()
test.throws(function () {
kBucket.get('foo')
}, TypeError)
test.done()
}
test['get retrieves null if no contacts'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.strictEqual(null, kBucket.get(new Buffer('foo')));
test.done();
};
test.expect(1)
var kBucket = new KBucket()
test.strictEqual(null, kBucket.get(new Buffer('foo')))
test.done()
}
test['get retrieves a contact that was added'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: new Buffer("a")};
kBucket.add(contact);
test.ok(bufferEqual(kBucket.get(new Buffer("a")).id, new Buffer("a")));
test.done();
};
test.expect(1)
var kBucket = new KBucket()
var contact = { id: new Buffer('a') }
kBucket.add(contact)
test.ok(bufferEqual(kBucket.get(new Buffer('a')).id, new Buffer('a')))
test.done()
}
test['get retrieves most recently added contact if same id'] = function (test) {
test.expect(3);
var kBucket = new KBucket();
var contact = {id: new Buffer("a"), foo: 'foo', bar: ':p', vectorClock: 0};
var contact2 = {id: new Buffer("a"), foo: 'bar', vectorClock: 1};
kBucket.add(contact);
kBucket.add(contact2);
test.ok(bufferEqual(kBucket.get(new Buffer("a")).id, new Buffer("a")));
test.equal(kBucket.get(new Buffer("a")).foo, 'bar');
test.strictEqual(kBucket.get(new Buffer("a")).bar, undefined);
test.done();
};
test.expect(3)
var kBucket = new KBucket()
var contact = { id: new Buffer('a'), foo: 'foo', bar: ':p', vectorClock: 0 }
var contact2 = { id: new Buffer('a'), foo: 'bar', vectorClock: 1 }
kBucket.add(contact)
kBucket.add(contact2)
test.ok(bufferEqual(kBucket.get(new Buffer('a')).id, new Buffer('a')))
test.equal(kBucket.get(new Buffer('a')).foo, 'bar')
test.strictEqual(kBucket.get(new Buffer('a')).bar, undefined)
test.done()
}
test['get retrieves contact from nested leaf node'] = function (test) {
test.expect(1);
var iString;
var kBucket = new KBucket({localNodeId: new Buffer('0000', 'hex')});
for (var i = 0; i < kBucket.numberOfNodesPerKBucket; i++) {
iString = i.toString('16');
if (iString.length < 2) {
iString = '0' + iString;
}
iString = '80' + iString; // make sure all go into "far away" bucket
kBucket.add({id: new Buffer(iString, 'hex')});
}
// cause a split to happen
kBucket.add({id: new Buffer('00' + iString, 'hex'), find: 'me'});
test.equal(kBucket.get(new Buffer('00' + iString, 'hex')).find, 'me');
test.done();
};
test.expect(1)
var kBucket = new KBucket({localNodeId: new Buffer([ 0x00, 0x00 ])})
for (var i = 0; i < kBucket.numberOfNodesPerKBucket; ++i) {
kBucket.add({ id: new Buffer([ 0x80, i ]) }) // make sure all go into "far away" bucket
}
// cause a split to happen
kBucket.add({ id: new Buffer([ 0x00, i ]), find: 'me' })
test.equal(kBucket.get(new Buffer([ 0x00, i ])).find, 'me')
test.done()
}

@@ -1,22 +0,20 @@

"use strict";
'use strict'
var KBucket = require('../index')
var KBucket = require('../index.js');
var test = module.exports = {}
var test = module.exports = {};
test['indexOf returns a contact with id that contains the same byte sequence as the test contact'] = function (test) {
test.expect(1)
var kBucket = new KBucket()
kBucket.add({ id: new Buffer('a') })
test.equal(kBucket._indexOf(new Buffer('a')), 0)
test.done()
}
test['indexOf returns a contact with id that contains the same byte sequence' +
' as the test contact'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
kBucket.add({id: new Buffer("a")});
test.equal(kBucket._indexOf(new Buffer("a")), 0);
test.done();
};
test['indexOf returns -1 if contact is not found'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
kBucket.add({id: new Buffer("a")});
test.equal(kBucket._indexOf(new Buffer("b")), -1);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
kBucket.add({ id: new Buffer('a') })
test.equal(kBucket._indexOf(new Buffer('b')), -1)
test.done()
}

@@ -1,48 +0,58 @@

"use strict";
'use strict'
var KBucket = require('../index')
var KBucket = require('../index.js');
var test = module.exports = {}
var test = module.exports = {};
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.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) {
test.expect(2);
var kBucket = new KBucket({localNodeId: new Buffer('0000', 'hex')});
for (var i = 0; i < kBucket.numberOfNodesPerKBucket; i++) {
var iString = i.toString('16');
if (iString.length < 2) {
iString = '0' + iString;
}
iString = '80' + iString; // make sure all go into "far away" bucket
kBucket.add({id: new Buffer(iString, 'hex')});
}
// cause a split to happen
kBucket.add({id: new Buffer('00' + iString, 'hex')});
// console.log(require('util').inspect(kBucket, false, null));
var contactToDelete = {id: new Buffer('8000', 'hex')};
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.expect(2)
var kBucket = new KBucket({ localNodeId: new Buffer([ 0x00, 0x00 ]) })
for (var i = 0; i < kBucket.numberOfNodesPerKBucket; ++i) {
kBucket.add({ id: new Buffer([ 0x80, i ]) }) // make sure all go into "far away" bucket
}
// cause a split to happen
kBucket.add({ id: new Buffer([ 0x00, i ]) })
// console.log(require('util').inspect(kBucket, false, null))
var contactToDelete = { id: new Buffer([ 0x80, 0x00 ]) }
test.equal(kBucket.high._indexOf(contactToDelete.id), 0)
kBucket.remove(new Buffer([ 0x80, 0x00 ]))
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();
};
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()
}
test['should generate event "removed" when removing from a split bucket'] = function (test) {
test.expect(2)
var kBucket = new KBucket({
localNodeId: new Buffer('') // need non-random localNodeId for deterministic splits
})
for (var i = 0; i < kBucket.numberOfNodesPerKBucket + 1; ++i) {
kBucket.add({ id: new Buffer('' + i) })
}
test.ok(!kBucket.bucket)
var contact = { id: new Buffer('a') }
kBucket.on('removed', function (removedContact) {
test.deepEqual(removedContact, contact)
})
kBucket.add(contact)
kBucket.remove(contact.id)
test.done()
}

@@ -1,122 +0,102 @@

"use strict";
'use strict'
var KBucket = require('../index')
var KBucket = require('../index.js');
var test = module.exports = {}
var test = module.exports = {};
test['adding a contact does not split K-bucket'] = function (test) {
test.expect(3);
var kBucket = new KBucket();
kBucket.add({id: new Buffer("a")});
test.ok(!kBucket.low);
test.ok(!kBucket.high);
test.ok(kBucket.bucket);
test.done();
};
test.expect(3)
var kBucket = new KBucket()
kBucket.add({ id: new Buffer('a') })
test.ok(!kBucket.low)
test.ok(!kBucket.high)
test.ok(kBucket.bucket)
test.done()
}
test['adding maximum number of contacts (per K-bucket) [20]' +
' into K-bucket does not split K-bucket'] = function (test) {
test.expect(3);
var kBucket = new KBucket();
for (var i = 0; i < kBucket.numberOfNodesPerKBucket; i++) {
kBucket.add({id: new Buffer("" + i)});
}
test.ok(!kBucket.low);
test.ok(!kBucket.high);
test.ok(kBucket.bucket);
test.done();
};
test['adding maximum number of contacts (per K-bucket) [20] into K-bucket does not split K-bucket'] = function (test) {
test.expect(3)
var kBucket = new KBucket()
for (var i = 0; i < kBucket.numberOfNodesPerKBucket; ++i) {
kBucket.add({ id: new Buffer('' + i) })
}
test.ok(!kBucket.low)
test.ok(!kBucket.high)
test.ok(kBucket.bucket)
test.done()
}
test['adding maximum number of contacts (per K-bucket) + 1 [21]' +
' into K-bucket splits the K-bucket'] = function (test) {
test.expect(3);
var kBucket = new KBucket();
for (var i = 0; i < kBucket.numberOfNodesPerKBucket + 1; i++) {
kBucket.add({id: new Buffer("" + i)});
}
test.ok(kBucket.low instanceof KBucket);
test.ok(kBucket.high instanceof KBucket);
test.ok(!kBucket.bucket);
test.done();
};
test['adding maximum number of contacts (per K-bucket) + 1 [21] into K-bucket splits the K-bucket'] = function (test) {
test.expect(3)
var kBucket = new KBucket()
for (var i = 0; i < kBucket.numberOfNodesPerKBucket + 1; ++i) {
kBucket.add({ id: new Buffer('' + i) })
}
test.ok(kBucket.low instanceof KBucket)
test.ok(kBucket.high instanceof KBucket)
test.ok(!kBucket.bucket)
test.done()
}
test['split buckets inherit options from parent bucket'] = function (test) {
var OPTIONS = ['arbiter', 'localNodeId', 'root', 'numberOfNodesPerKBucket',
'numberOfNodesToPing'];
test.expect(2 * OPTIONS.length);
var kBucket = new KBucket();
var _options = {};
OPTIONS.forEach(function(option){
_options[option] = kBucket[option];
});
for (var i = 0; i < kBucket.numberOfNodesPerKBucket + 1; i++) {
kBucket.add({id: new Buffer("" + i)});
}
OPTIONS.forEach(function(option){
test.strictEqual(kBucket.low[option], _options[option]);
test.strictEqual(kBucket.high[option], _options[option]);
});
test.done();
};
var OPTIONS = ['arbiter', 'localNodeId', 'root', 'numberOfNodesPerKBucket', 'numberOfNodesToPing']
test.expect(2 * OPTIONS.length)
var kBucket = new KBucket()
var _options = {}
OPTIONS.forEach(function (option) { _options[option] = kBucket[option] })
for (var i = 0; i < kBucket.numberOfNodesPerKBucket + 1; ++i) {
kBucket.add({ id: new Buffer('' + i) })
}
OPTIONS.forEach(function (option) {
test.strictEqual(kBucket.low[option], _options[option])
test.strictEqual(kBucket.high[option], _options[option])
})
test.done()
}
test['split buckets contain all added contacts'] = function (test) {
test.expect(20 /*numberOfNodesPerKBucket*/ + 2);
var kBucket = new KBucket({localNodeId: new Buffer('00', 'hex')});
var foundContact = {};
for (var i = 0; i < kBucket.numberOfNodesPerKBucket + 1; i++) {
var iString = i.toString('16');
if (iString.length < 2) {
iString = '0' + iString;
}
kBucket.add({id: new Buffer(iString, 'hex')});
foundContact[iString] = false;
test.expect(20 /* numberOfNodesPerKBucket */ + 2)
var kBucket = new KBucket({localNodeId: new Buffer([ 0x00 ])})
var foundContact = {}
for (var i = 0; i < kBucket.numberOfNodesPerKBucket + 1; ++i) {
kBucket.add({ id: new Buffer([ i ]) })
foundContact[i] = false
}
var traverse = function (node) {
if (!node.bucket) {
traverse(node.low)
traverse(node.high)
} else {
node.bucket.forEach(function (contact) {
foundContact[parseInt(contact.id.toString('hex'), 16)] = true
})
}
var traverse = function (node) {
if (!node.bucket) {
traverse(node.low);
traverse(node.high);
} else {
node.bucket.forEach(function (contact) {
foundContact[contact.id.toString('hex')] = true;
});
}
};
traverse(kBucket);
Object.keys(foundContact).forEach(function (key) {
test.ok(foundContact[key], key);
});
test.ok(!kBucket.bucket);
test.done();
};
}
traverse(kBucket)
Object.keys(foundContact).forEach(function (key) { test.ok(foundContact[key], key) })
test.ok(!kBucket.bucket)
test.done()
}
test['when splitting buckets the "far away" bucket should be marked' +
' to prevent splitting "far away" bucket'] = function (test) {
test.expect(5);
var kBucket = new KBucket({localNodeId: new Buffer('00', 'hex')});
for (var i = 0; i < kBucket.numberOfNodesPerKBucket + 1; i++) {
var iString = i.toString('16');
if (iString.length < 2) {
iString = '0' + iString;
}
kBucket.add({id: new Buffer(iString, 'hex')});
test['when splitting buckets the "far away" bucket should be marked to prevent splitting "far away" bucket'] = function (test) {
test.expect(5)
var kBucket = new KBucket({ localNodeId: new Buffer([ 0x00 ]) })
for (var i = 0; i < kBucket.numberOfNodesPerKBucket + 1; ++i) {
kBucket.add({ id: new Buffer([ i ]) })
}
// above algorithm will split low bucket 4 times and put 0x00 through 0x0f
// in the low bucket, and put 0x10 through 0x14 in high bucket
// since localNodeId is 0x00, we expect every high bucket to be "far" and
// therefore marked as "dontSplit = true"
// there will be one "low" bucket and four "high" buckets (test.expect(5))
var traverse = function (node, dontSplit) {
if (!node.bucket) {
traverse(node.low, false)
traverse(node.high, true)
} else {
if (dontSplit) test.ok(node.dontSplit)
else test.ok(!node.dontSplit)
}
// above algorithm will split low bucket 4 times and put 0x00 through 0x0f
// in the low bucket, and put 0x10 through 0x14 in high bucket
// since localNodeId is 0x00, we expect every high bucket to be "far" and
// therefore marked as "dontSplit = true"
// there will be one "low" bucket and four "high" buckets (test.expect(5))
var traverse = function (node, dontSplit) {
if (!node.bucket) {
traverse(node.low, false);
traverse(node.high, true);
} else {
if (dontSplit) {
test.ok(node.dontSplit);
} else {
test.ok(!node.dontSplit);
}
}
};
traverse(kBucket);
test.done();
};
}
traverse(kBucket)
test.done()
}

@@ -1,40 +0,33 @@

"use strict";
'use strict'
var KBucket = require('../index')
var KBucket = require('../index.js');
var test = module.exports = {}
var test = module.exports = {};
test['toArray should return empty array if no contacts'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
test.equal(kBucket.toArray().length, 0);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
test.equal(kBucket.toArray().length, 0)
test.done()
}
test['toArray should return all contacts in an array arranged from low to high buckets'] = function (test) {
test.expect(22);
var iString;
var expectedIds = [];
var kBucket = new KBucket({localNodeId: new Buffer('0000', 'hex')});
for (var i = 0; i < kBucket.numberOfNodesPerKBucket; i++) {
iString = i.toString('16');
if (iString.length < 2) {
iString = '0' + iString;
}
iString = '80' + iString; // make sure all go into "far away" bucket
expectedIds.push(iString);
kBucket.add({id: new Buffer(iString, 'hex')});
}
// cause a split to happen
kBucket.add({id: new Buffer('00' + iString, 'hex')});
// console.log(require('util').inspect(kBucket, {depth: null}));
var contacts = kBucket.toArray();
// console.log(require('util').inspect(contacts, {depth: null}));
test.equal(contacts.length, kBucket.numberOfNodesPerKBucket + 1);
test.equal(contacts[0].id.toString('hex'), '00' + iString);
contacts.shift(); // get rid of low bucket contact
for (i = 0; i < kBucket.numberOfNodesPerKBucket; i++) {
test.equal(contacts[i].id.toString('hex'), expectedIds[i]);
}
test.done();
};
test.expect(22)
var kBucket = new KBucket({ localNodeId: new Buffer([ 0x00, 0x00 ]) })
var expectedIds = []
for (var i = 0; i < kBucket.numberOfNodesPerKBucket; ++i) {
kBucket.add({ id: new Buffer([ 0x80, i ]) }) // make sure all go into "far away" bucket
expectedIds.push(0x80 * 256 + i)
}
// cause a split to happen
kBucket.add({ id: new Buffer([ 0x00, 0x80, i - 1 ]) })
// console.log(require('util').inspect(kBucket, {depth: null}))
var contacts = kBucket.toArray()
// console.log(require('util').inspect(contacts, {depth: null}))
test.equal(contacts.length, kBucket.numberOfNodesPerKBucket + 1)
test.equal(parseInt(contacts[0].id.toString('hex'), 16), 0x80 * 256 + i - 1)
contacts.shift() // get rid of low bucket contact
for (i = 0; i < kBucket.numberOfNodesPerKBucket; ++i) {
test.equal(parseInt(contacts[i].id.toString('hex'), 16), expectedIds[i])
}
test.done()
}

@@ -1,69 +0,87 @@

"use strict";
'use strict'
var bufferEqual = require('buffer-equal')
var KBucket = require('../index')
var KBucket = require('../index.js'),
bufferEqual = require('buffer-equal');
var test = module.exports = {}
var test = module.exports = {};
test['invalid index results in exception'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: new Buffer("a")};
kBucket.add(contact);
try {
kBucket._update(contact, 1);
} catch (exception) {
test.ok(true);
}
test.done();
};
test.expect(1)
var kBucket = new KBucket()
var contact = { id: new Buffer('a') }
kBucket.add(contact)
try {
kBucket._update(contact, 1)
} catch (exception) {
test.ok(true)
}
test.done()
}
test['deprecated vectorClock results in contact drop'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: new Buffer("a"), vectorClock: 3};
kBucket.add(contact);
kBucket._update({id: new Buffer("a"), vectorClock: 2}, 0);
test.equal(kBucket.bucket[0].vectorClock, 3);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
var contact = { id: new Buffer('a'), vectorClock: 3 }
kBucket.add(contact)
kBucket._update({ id: new Buffer('a'), vectorClock: 2 }, 0)
test.equal(kBucket.bucket[0].vectorClock, 3)
test.done()
}
test['equal vectorClock results in contact marked as most recent'] = function (test) {
test.expect(1);
var kBucket = new KBucket();
var contact = {id: new Buffer("a"), vectorClock: 3};
kBucket.add(contact);
kBucket.add({id: new Buffer("b")});
kBucket._update(contact, 0);
test.equal(kBucket.bucket[1], contact);
test.done();
};
test.expect(1)
var kBucket = new KBucket()
var contact = { id: new Buffer('a'), vectorClock: 3 }
kBucket.add(contact)
kBucket.add({ id: new Buffer('b') })
kBucket._update(contact, 0)
test.equal(kBucket.bucket[1], contact)
test.done()
}
test['more recent vectorClock results in contact update and contact being' +
' marked as most recent'] = function (test) {
test.expect(4);
var kBucket = new KBucket();
var contact = {id: new Buffer("a"), old: 'property', vectorClock: 3};
kBucket.add(contact);
kBucket.add({id: new Buffer("b")});
kBucket._update({id: new Buffer("a"), newer: 'property', vectorClock: 4}, 0);
test.ok(bufferEqual(kBucket.bucket[1].id, contact.id));
test.equal(kBucket.bucket[1].vectorClock, 4);
test.strictEqual(kBucket.bucket[1].old, undefined);
test.strictEqual(kBucket.bucket[1].newer, 'property');
test.done();
};
test['more recent vectorClock results in contact update and contact being marked as most recent'] = function (test) {
test.expect(4)
var kBucket = new KBucket()
var contact = { id: new Buffer('a'), old: 'property', vectorClock: 3 }
kBucket.add(contact)
kBucket.add({ id: new Buffer('b') })
kBucket._update({ id: new Buffer('a'), newer: 'property', vectorClock: 4 }, 0)
test.ok(bufferEqual(kBucket.bucket[1].id, contact.id))
test.equal(kBucket.bucket[1].vectorClock, 4)
test.strictEqual(kBucket.bucket[1].old, undefined)
test.strictEqual(kBucket.bucket[1].newer, 'property')
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();
};
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()
}
test['should generate event "updated" when updating a split bucket'] = function (test) {
test.expect(3)
var kBucket = new KBucket({
localNodeId: new Buffer('') // need non-random localNodeId for deterministic splits
})
for (var i = 0; i < kBucket.numberOfNodesPerKBucket + 1; ++i) {
kBucket.add({ id: new Buffer('' + i) })
}
test.ok(!kBucket.bucket)
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