Skip to content

Commit

Permalink
doc: code comments.
Browse files Browse the repository at this point in the history
  • Loading branch information
BruceWind committed Sep 8, 2024
1 parent 82bb4c8 commit e90ee8b
Showing 1 changed file with 43 additions and 26 deletions.
69 changes: 43 additions & 26 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,24 @@ import fs from 'node:fs';
import ping from 'ping';
import globalAgent from 'global-agent';


import cliProgress from 'cli-progress';
const terminalBarUI = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);

import net from 'node:net';

globalAgent.bootstrap();

// Function to read and parse a JSON file
function readJsonFile(filePath) {
const jsonData = fs.readFileSync(filePath, 'utf-8');
return JSON.parse(jsonData);
}


const OFFICIAL_CDN_IPs_URL = "https://api.gcore.com/cdn/public-ip-list"

//Read IP from gcore_cdn_ip_ranges.json located in the project's root directory and update it weekly or daily.
const { localRanges } = readJsonFile("./gcore_cdn_ip_ranges.json")



// This line had set been disable, due to Gcore without IP in China mainland.
//const PREFIX_IP_LOCALATION = "http://ip2c.org/" // It is used to query which country belongs to.

Expand All @@ -35,24 +32,23 @@ import { Netmask } from 'netmask';
// In case script can not find any available IPs, You should try to increase {THRESHOLD} to 140.
const THRESHOLD = 200;


const PING_THREADS = 50;
let countOfBeingProcess = 0;

// Function to execute a command as a Promise
function execPromise(command) {
return new Promise(function (resolve, reject) {
exec(command, (error, stdout, stderr) => {
if (error) {
reject(error);
return;
}

resolve(stdout.trim());
});
});
}


// Function to fetch data with a timeout
function fetchWithTimeout(url, httpSettings, timeout) {
return Promise.race([
fetch(url, httpSettings),
Expand All @@ -62,12 +58,9 @@ function fetchWithTimeout(url, httpSettings, timeout) {
]);
}



let ips = [];


//
// Main function to orchestrate the IP scanning process
async function main() {
try {
const httpSettings = {
Expand All @@ -88,35 +81,39 @@ async function main() {
console.warn("Request went wrong but it's ok. It will use local JSON file to read IP ranges.");
}


// items of this are CIDR, its doc is here https://datatracker.ietf.org/doc/rfc4632/.
const arrOfIPRanges = json ? json["addresses"] : localRanges;

if (!json) {
console.warn("Use local IP ranges.");
}

for (const ipRnage of arrOfIPRanges) {
let netmask = new Netmask(ipRnage);
// Iterate through IP ranges and collect IPs
for (const ipRange of arrOfIPRanges) {
let netmask = new Netmask(ipRange);

netmask.forEach(async (ip) => {
const ipstr = ip + '';
let ip = netmask.first;
while (ip) {
const ipstr = ip.toString();
// Check if the last octet of the IP address is less than 100
if (parseInt(ipstr.split('.')[3]) < 100) {
ips.push(ip);
// console.log('jump ' + ipstr);
ips.push(ipstr);
}
})

ip = netmask.next(ip);
if (ip && parseInt(ip.toString().split('.')[3]) > 150) {
break;
}
}
}


console.log(`Current progress:`);

terminalBarUI.start(ips.length, 0);
let unsortedArr = [];
for (let i = 0; i < ips.length; i++) {
const ip = ips[i];

// Check if we're at the processing limit or near the end of the IP list
if (countOfBeingProcess > PING_THREADS || i > ips.length - 20) {
terminalBarUI.update(i);
countOfBeingProcess++;
Expand All @@ -125,11 +122,14 @@ async function main() {
unsortedArr.push({ ip, latency: avgLatency });
}
countOfBeingProcess--;
// Check if we need to trim the unsorted array
if (unsortedArr.length > 150) {
// Sort the array by latency in ascending order
unsortedArr = unsortedArr.sort((a, b) => {
return a.latency - b.latency;
});
unsortedArr.slice(100, 150);
// Remove the last 50 items (highest latencies)
unsortedArr.splice(100, 50);
console.warn('removed 50 IPs.');
}
}
Expand Down Expand Up @@ -181,8 +181,10 @@ async function main() {
}
}

// Delay the execution of the main function
setTimeout(main, 100);

// Function to query latency using ping
async function queryLatency(ip) {
try {
const result = await ping.promise.probe(ip, {
Expand All @@ -199,6 +201,7 @@ async function queryLatency(ip) {

const TIMEOUT = 8600;

// Function to query TCP latency
async function queryTCPLatency(ip) {
const port = 443;
const start = process.hrtime.bigint();
Expand Down Expand Up @@ -234,24 +237,38 @@ async function queryTCPLatency(ip) {
}
}


// Function to query average latency using multiple methods
async function queryAvgLatency(ip) {
try {
await queryTCPLatency(ip); // this line looks like useless, but In my opinion, this can make connection reliable.
// Initial TCP latency query to establish connection
await queryTCPLatency(ip);

// Perform ping latency check
const pingLatency = await queryLatency(ip);
// Check if ping latency exceeds threshold
if (pingLatency > THRESHOLD + 50) return pingLatency;

// Perform multiple TCP latency checks
const latency1 = await queryTCPLatency(ip);
// Check if first TCP latency exceeds threshold
if (latency1 > THRESHOLD + 50) return latency1;

const latency2 = await queryTCPLatency(ip);
// Check if second TCP latency exceeds threshold
if (latency2 > THRESHOLD + 50) return latency2;

// Check for undefined latencies
if (latency1 === undefined || latency2 === undefined) throw new Error('latencies are undefined');
const latency3 = await queryTCPLatency(ip);

const result = Math.round((latency1 + latency2) / 2);
// Perform an additional TCP latency check (unused in calculation)
const latency3 = await queryTCPLatency(ip);

// Calculate and return the average of the two valid TCP latencies
const result = Math.round((latency1 + latency2 + latency3) / 3);
return result;
}
catch (e) {
// Error handling for unreachable IP
console.log(`${ip} is not reachable.`, e.message);
}
return 1000;
Expand Down

0 comments on commit e90ee8b

Please sign in to comment.