Comparing version
@@ -16,3 +16,3 @@ 'use strict'; | ||
while (lastIp = this.subnet.nextIp(lastIp)) { | ||
callback(lastIp); | ||
callback(lastIp, this.subnet.buildProgressData(lastIp)); | ||
} | ||
@@ -24,5 +24,5 @@ } | ||
while (lastIp = this.subnet.nextIp(lastIp)) { | ||
await callback(lastIp); | ||
await callback(lastIp, this.subnet.buildProgressData(lastIp)); | ||
} | ||
} | ||
}; |
@@ -85,2 +85,10 @@ 'use strict'; | ||
const ipStringToArray = ipStr => ipStr.split('.').map(part => part * 1); | ||
const calculateIteration = (mask, ip) => { | ||
const binaryIp = toBinaryArray(ip); | ||
const binaryIteration = binaryIp.slice(mask, binaryIp.length); | ||
return parseInt(binaryIteration.join(''), 2) + 1; | ||
}; | ||
class SubnetIpV4 { | ||
@@ -97,3 +105,3 @@ constructor(subnet) { | ||
} | ||
const incrementedIp = incrementIp(lastIp.split('.').map(part => part * 1)); | ||
const incrementedIp = incrementIp(ipStringToArray(lastIp)); | ||
if (!incrementedIp || !firstNBitsMatch(incrementedIp, this.ip, this.mask)) { | ||
@@ -104,2 +112,13 @@ return null; | ||
} | ||
buildProgressData(iteratedIp) { | ||
const ipArray = ipStringToArray(iteratedIp); | ||
if (!firstNBitsMatch(ipArray, this.ip, this.mask)) { | ||
throw new Error('The provided IP address does not match the subnet'); | ||
} | ||
const allIps = Math.pow(2, 32 - this.mask); | ||
const iteration = calculateIteration(this.mask, ipArray); | ||
const completionPercentage = Math.round(iteration / (allIps / 100)); | ||
return {allIps, iteration, completionPercentage}; | ||
} | ||
} | ||
@@ -106,0 +125,0 @@ |
{ | ||
"name": "ipterate", | ||
"version": "1.0.3", | ||
"version": "1.1.0", | ||
"description": " A small utility library to allow you to iterate through all IPs within a given subnet. Remains efficient no matter how many IPs there are in the range.", | ||
"main": "index.js", | ||
"directories": { | ||
"test": "test", | ||
"lib": "lib" | ||
}, | ||
"scripts": { | ||
"test": "node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha --report lcovonly -- --recursive && cat ./coverage/lcov.info | node ./node_modules/coveralls/bin/coveralls.js" | ||
"test": "node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha --report lcovonly -- --recursive", | ||
"send-coverage": "cat ./coverage/lcov.info | node ./node_modules/coveralls/bin/coveralls.js" | ||
}, | ||
"repository": "https://github.com/kamiljano/ipterate", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/kamiljano/ipterate.git" | ||
}, | ||
"homepage": "https://github.com/kamiljano/ipterate", | ||
"keywords": [ | ||
@@ -16,3 +25,3 @@ "ip", | ||
], | ||
"author": "kgjanowski@gmail.com", | ||
"author": "Kamil Janowski <kgjanowski@gmail.com>", | ||
"license": "ISC", | ||
@@ -19,0 +28,0 @@ "devDependencies": { |
@@ -11,2 +11,4 @@ [](https://travis-ci.org/kamiljano/ipterate) | ||
## Basic usage | ||
For instance the following code | ||
@@ -39,3 +41,3 @@ | ||
If you want to perform an asynchronous action, make sure that your function returns a promise and call `iterateAsync` | ||
If you want to perform an asynchronous action, make sure that your delegate returns a promise and call `iterateAsync` | ||
instead. `iterateAsync` itself returns a promise and will wait for the resolution of the promise returned by | ||
@@ -51,4 +53,16 @@ your delegate, before it provides you with another IP. | ||
## Iteration information | ||
Iterating through large sets of IPs might take a while. For this reason you might want to track the progress of your iteration. | ||
In the second parameter the `iterate` and `iterateAsync` provide itaration information to your delegate function. | ||
ipterate.range('0.0.0.0/0').iterate((ip, data) => { | ||
console.log(`All IPs available in this subnet: ${data.allIps}`); | ||
console.log(`Current iteration: ${data.iteration}`); //starts from 1 | ||
console.log(`Completion percentage: ${data.completionPercentage}`); // an integer number between 0 and 100 | ||
// calculated based on allIps and iteration | ||
}); | ||
# Installation | ||
npm install --save ipterate |
@@ -21,13 +21,29 @@ 'use strict'; | ||
expect(callback).to.have.been.called.exactly(256); | ||
expect(callback).to.have.been.called.with('255.255.255.0'); | ||
expect(callback).to.have.been.called.with('255.255.255.255'); | ||
expect(callback).to.have.been.called.with('255.255.255.0', { | ||
allIps: 256, | ||
iteration: 1, | ||
completionPercentage: 0 | ||
}); | ||
expect(callback).to.have.been.called.with('255.255.255.255', { | ||
allIps: 256, | ||
iteration: 256, | ||
completionPercentage: 100 | ||
}); | ||
}); | ||
it('WHEN triggering the iterateAsync(), THEN all IPs within the subnet are properly processed', async () => { | ||
await new IpRange('255.255.255.0/24').iterateAsync(async ip => { | ||
callback(ip); | ||
await new IpRange('255.255.255.0/24').iterateAsync(async (ip, data) => { | ||
callback(ip, data); | ||
}); | ||
expect(callback).to.have.been.called.exactly(256); | ||
expect(callback).to.have.been.called.with('255.255.255.0'); | ||
expect(callback).to.have.been.called.with('255.255.255.255'); | ||
expect(callback).to.have.been.called.with('255.255.255.0', { | ||
allIps: 256, | ||
iteration: 1, | ||
completionPercentage: 0 | ||
}); | ||
expect(callback).to.have.been.called.with('255.255.255.255', { | ||
allIps: 256, | ||
iteration: 256, | ||
completionPercentage: 100 | ||
}); | ||
}); | ||
@@ -34,0 +50,0 @@ |
@@ -76,2 +76,32 @@ 'use strict'; | ||
}); | ||
describe('WHEN the string is a valid subnet identifier AND the buildProgressData() is called', () => { | ||
it('with a valid IP, but one that does not match the subnet, THEN an error is thrown', () => { | ||
const subnet = new SubnetIpV4('255.255.255.0/24'); | ||
expectError(() => subnet.buildProgressData('0.0.0.0')); | ||
}); | ||
it('with a valid IP that matches the subnet, THEN a valid number of all IPs is returned', () => { | ||
const subnet = new SubnetIpV4('255.255.255.0/24'); | ||
expect(subnet.buildProgressData('255.255.255.0').allIps).to.equal(256); | ||
}); | ||
it('with a valid max IP that matches the subnet, THEN a valid number of all IPs is returned', () => { | ||
const subnet = new SubnetIpV4('0.0.0.0/0'); | ||
expect(subnet.buildProgressData('255.255.255.255').allIps).to.equal(Math.pow(2, 32)); | ||
expect(subnet.buildProgressData('255.255.255.255').iteration).to.equal(Math.pow(2, 32)); | ||
}); | ||
it('with a valid IP that matches the subnet, THEN a valid index is returned', () => { | ||
const subnet = new SubnetIpV4('255.255.0.0/16'); | ||
expect(subnet.buildProgressData('255.255.1.0').iteration).to.equal(257); | ||
}); | ||
it('with a valid IP that matches the subnet, THEN a valid completion percentage is returned', () => { | ||
const subnet = new SubnetIpV4('255.255.255.0/24'); | ||
expect(subnet.buildProgressData('255.255.255.128').completionPercentage).to.equal(50); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
14342
33.82%284
24.02%0
-100%65
27.45%1
-50%