Skip to content

Commit

Permalink
feat(version): Release v1.0.4
Browse files Browse the repository at this point in the history
  • Loading branch information
Alice39s committed Jan 15, 2025
1 parent 095230a commit 60863e8
Show file tree
Hide file tree
Showing 17 changed files with 748 additions and 235 deletions.
58 changes: 57 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,63 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.3] - 2025-01-03
# Changelog

## [1.0.4] - 2025-01-16

### 💫 Added

#### Algorithm Refactoring

- ICMP, TCP, and HTTP(2) latency tests now start simultaneously to shorten the testing cycle
- Implemented dynamic buffer pool size adjustment to enhance download and upload speed testing algorithms, saving more bandwidth
- Improved upload speed testing algorithm's adaptability, now dynamically adjusting buffer pool size based on network conditions

#### CLI

- Added `--privacy` flag to support IP address desensitization
- Enhanced geographic location information display with country flag emojis
- Improved IP address display, now by default hiding /24 and /48 segments of IPv4 and IPv6 addresses

#### Logging and Debugging

- Enhanced logging to provide more detailed speed testing process information
- Optimized error handling and retry mechanisms
- Supported more flexible progress callback functions

### 🔧 Changed

#### Dependency Management

- Added new dependencies:
- `@types/cli-progress`: CLI progress bar type definitions
- `ip-address`: IP address processing tool
- `cli-progress`: Command-line progress bar component

#### Partial Type Refactoring

- Improved type definitions to enhance type safety

### 🐞 Bug Fixes and Stability

#### Error Handling

- Improved DNS resolution and network request error handling
- Added multiple retry mechanisms to increase network testing robustness
- Fixed potential boundary condition issues from previous versions

#### Performance Optimization

- Optimized sampling and statistical algorithms for speed testing
- Reduced unnecessary performance overhead
- Improved accuracy and consistency of speed test results

### Documentation Updates

- Added detailed comments for new functions and configurations
- Improved internal code documentation to enhance code readability

## 1.0.3 - 2025-01-03

### Added

Expand Down
Binary file modified bun.lockb
100644 → 100755
Binary file not shown.
33 changes: 33 additions & 0 deletions common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { SpeedWindow } from './types';

export function createProgressUpdater(
onProgress?: (speed: number, bytesTransferred: number) => void
) {
let speedWindow: SpeedWindow[] = [];
let totalBytesTransferred = 0;

return {
update: (chunkSize: number) => {
const now = Date.now();
totalBytesTransferred += chunkSize;

speedWindow.push({ timestamp: now, bytes: totalBytesTransferred });

// Keep only the last 5 seconds of data
speedWindow = speedWindow.filter(entry => now - entry.timestamp <= 5000);

if (speedWindow.length >= 2) {
const first = speedWindow[0];
const last = speedWindow[speedWindow.length - 1];
const duration = (last.timestamp - first.timestamp) / 1000; // seconds
const bytes = last.bytes - first.bytes;
const speed = (bytes * 8) / duration; // bits per second

if (onProgress) {
onProgress(speed, totalBytesTransferred);
}
}
},
getTotalBytesTransferred: () => totalBytesTransferred
};
}
Empty file added index.ts
Empty file.
Empty file added logger.ts
Empty file.
125 changes: 64 additions & 61 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,64 +1,67 @@
{
"name": "aqua-speed",
"module": "./src/cli.ts",
"version": "1.0.3",
"description": "A modern network speed test CLI built with Bun and TypeScript.",
"type": "module",
"scripts": {
"build": "bun build ./src/cli.ts --outdir dist",
"start": "bun run src/cli.ts",
"dev": "bun --watch src/cli.ts",
"test": "bun test",
"lint": "biome check --write",
"format": "biome format --write"
},
"author": "Alice39s",
"license": "GPL-3.0-only",
"keywords": [
"speedtest",
"cli",
"cdn",
"network",
"performance",
"bun"
],
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/bogon": "^1.0.2",
"@types/bun": "latest",
"@types/ping": "^0.4.4",
"@types/psl": "^1.1.3"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
"@types/user-agents": "^1.0.4",
"bogon": "^1.1.0",
"bufferutil": "^4.0.8",
"chalk": "^5.4.0",
"commander": "^12.1.0",
"ora": "^8.1.1",
"ping": "^0.4.4",
"psl": "^1.15.0",
"table": "^6.9.0",
"undici": "^7.2.0",
"user-agents": "^1.1.396",
"ws": "^8.18.0"
},
"supportedArchitectures": {
"os": [
"win32",
"darwin",
"linux"
"name": "aqua-speed",
"module": "./src/cli.ts",
"version": "1.0.4",
"description": "A modern network speed test CLI built with Bun and TypeScript.",
"type": "module",
"scripts": {
"build": "bun build ./src/cli.ts --outdir dist",
"start": "bun run src/cli.ts",
"dev": "bun --watch src/cli.ts",
"test": "bun test",
"lint": "biome check --write",
"format": "biome format --write"
},
"author": "Alice39s",
"license": "GPL-3.0-only",
"keywords": [
"speedtest",
"cli",
"cdn",
"network",
"performance",
"bun"
],
"cpu": [
"x64",
"arm64"
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/bogon": "^1.0.2",
"@types/bun": "latest",
"@types/ping": "^0.4.4",
"@types/psl": "^1.1.3"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
"@types/cli-progress": "^3.11.6",
"@types/user-agents": "^1.0.4",
"bogon": "^1.1.0",
"bufferutil": "^4.0.8",
"chalk": "^5.4.0",
"cli-progress": "^3.12.0",
"commander": "^12.1.0",
"ip-address": "^10.0.1",
"ora": "^8.1.1",
"ping": "^0.4.4",
"psl": "^1.15.0",
"table": "^6.9.0",
"undici": "^7.2.0",
"user-agents": "^1.1.396",
"ws": "^8.18.0"
},
"supportedArchitectures": {
"os": [
"win32",
"darwin",
"linux"
],
"cpu": [
"x64",
"arm64"
]
},
"trustedDependencies": [
"@biomejs/biome",
"bufferutil"
]
},
"trustedDependencies": [
"@biomejs/biome",
"bufferutil"
]
}
}
100 changes: 74 additions & 26 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,73 +2,120 @@ import { program } from 'commander';
import { runSpeedTest } from '@/controllers/runSpeedTest';
import { description, version } from '../package.json';
import { formatTestResults } from '@/utils/format';
import type { TestConfig, TestDisplay } from '@/types';
import type { TestConfig, TestDisplay, IpGeoResponse } from '@/types';
import { mergeTestConfig, prepareDisplayInfo } from '@/controllers/processOptions';
import { getIpGeolocation, getIpGeoOnly } from '@/models/tools/getGeoIp';
import { resolveDns } from '@/models/tools/dnsResolver';
import chalk from 'chalk';
import { manageDebugMode, isDebugMode } from './utils/common';
import { manageDebugMode, isDebugMode, maskIpAddress, countryCodeToFlagEmoji } from './utils/common';

if (isDebugMode()) {
console.log(chalk.green('Debug mode enabled'));
}

/**
* Display Start
* @param display Test Display
* @type {TestDisplay}
* @returns Promise<void>
* Display ASCII Logo
*/
async function displayStart(display: TestDisplay, config: TestConfig): Promise<void> {
console.log(chalk.cyan("\n _____ _ "));
console.log(chalk.cyan(" /\\ / ____| | |"));
console.log(chalk.cyan(" / \\ __ _ _ _ __ _ | (___ _ __ ___ ___ __| |"));
console.log(chalk.cyan(" / /\\ \\ / _` | | | |/ _` | \\___ \\| '_ \\ / _ \\/ _ \\/ _` |"));
console.log(chalk.cyan(" / ____ \\ (_| | |_| | (_| | ____) | |_) | __/ __/ (_| |"));
console.log(chalk.cyan(" /_/ \\_\\__, |\\__,_|\\__,_| |_____/| .__/ \\___|\\___|\\__,_|"));
console.log(chalk.cyan(" | | | | "));
console.log(chalk.cyan(" |_| |_| "));
function displayLogo(): void {
const logoLines = [
"\n _____ _ ",
" /\\ / ____| | |",
" / \\ __ _ _ _ __ _ | (___ _ __ ___ ___ __| |",
" / /\\ \\ / _` | | | |/ _` | \\___ \\| '_ \\ / _ \\/ _ \\/ _` |",
" / ____ \\ (_| | |_| | (_| | ____) | |_) | __/ __/ (_| |",
" /_/ \\_\\__, |\\__,_|\\__,_| |_____/| .__/ \\___|\\___|\\__,_|",
" | | | | ",
" |_| |_| \n"
];

for (const line of logoLines) console.log(chalk.cyan(line));
}

/**
* Display Version Info
*/
function displayVersion(): void {
console.warn(chalk.bold(`\nAqua Speed v${version}\n`));
console.warn(chalk.gray(` - ${description}\n`));
}

/**
* Format and display location info
*/
function formatLocationInfo(ipInfo: IpGeoResponse): string[] {
const { ip, region, country, org, anycast } = ipInfo;
const location = anycast ? 'Anycast IP' : `${region}, ${country}`;

return [
chalk.gray(" IP: ") + chalk.white(`${ip}`) + chalk.gray(` (${org})`),
chalk.gray(" Location: ") + chalk.white(location)
];
}

/**
* Display server information
*/
async function displayServerInfo(config: TestConfig): Promise<void> {
console.log(chalk.yellow('Test Configuration:'));

try {
const resResult = await resolveDns(config.server);
if (resResult.ip) {
const ipInfo = await getIpGeoOnly(resResult.ip);
const { ip, region, country, org } = ipInfo;
const location = `${region}, ${country}`;

console.log(chalk.gray(" IP: ") + chalk.white(`${ip}`) + chalk.gray(` (${org})`));
console.log(chalk.gray(" Location: ") + chalk.white(location));
const locationInfo = formatLocationInfo(ipInfo);
for (const line of locationInfo) console.log(line);
}
} catch (error) {
console.error(chalk.red('Error details:'), error);
process.exit(1);
}
}

/**
* Display test configuration
*/
function displayTestConfig(display: TestDisplay): void {
for (const [key, value] of Object.entries(display.testInfo)) {
console.log(chalk.gray(` ${key}: `) + chalk.white(value));
}
if (display.flags.length) {
console.log(chalk.gray(" Flags: ") + chalk.white(display.flags.join(', ')));
}
}

/**
* Display client information
*/
async function displayClientInfo(config: TestConfig): Promise<void> {
console.log(chalk.yellow('\nClient Information:'));


try {
const ipInfo = await getIpGeolocation(config);
const { ip, region, country, org } = ipInfo;
const location = `${region}, ${country}`;
const countryEmoji = countryCodeToFlagEmoji(country);
const location = `${countryEmoji} ${region}`;
const maskedIp = maskIpAddress(ip, config.privacy);

console.log(chalk.gray(" IP: ") + chalk.white(`${ip}`) + chalk.gray(` (${org})`));
console.log(chalk.gray(" IP: ") + chalk.white(`${maskedIp}`) + chalk.gray(` (${org})`));
console.log(chalk.gray(" Location: ") + chalk.white(location));
} catch (error) {
console.error(chalk.red('Error details:'), error);
process.exit(1);
}
}

/**
* Display Start
* @param display Test Display
* @type {TestDisplay}
* @returns Promise<void>
*/
async function displayStart(display: TestDisplay, config: TestConfig): Promise<void> {
displayLogo();
displayVersion();
await displayServerInfo(config);
displayTestConfig(display);
await displayClientInfo(config);

console.log(chalk.cyan('\nInitializing speed test...\n'));
}
Expand Down Expand Up @@ -116,7 +163,8 @@ async function main() {
.option('--sn <name>', 'Speed test server name')
.option('-t, --thread <number>', 'Number of concurrent connections', Number.parseInt)
.option('--timeout <seconds>', 'Test timeout in seconds', Number.parseInt)
.option('--debug', 'Debug mode')
.option('--debug', 'Debug mode', false)
.option('--privacy', 'Privacy mode (Display the local address instead of real IP)', false)
.option('--type <type>', 'Default: SingleFile, options: LibreSpeed, Ookla, Cloudflare', 'Cloudflare') // TODO: Ookla is not supported yet
// .option('--ns, --no-speedtest', 'Disable speed test')
// .option('--nl, --no-latency', 'Disable latency test')
Expand All @@ -143,12 +191,12 @@ async function main() {
timeout: config.timeout,
type: config.type
});

const endTime = process.hrtime(startTime); // End Timing
const elapsedTimeInS = endTime[0] + (endTime[1] / 1e9); // Converts to seconds
formatTestResults(result, display);
display.results.info['Total Time'] = `${elapsedTimeInS.toFixed(2)}s`;

displayResults(display);

process.exit(0);
Expand Down
Loading

0 comments on commit 60863e8

Please sign in to comment.