@qodalis/cli-speed-test 0.0.3 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md DELETED
@@ -1,17 +0,0 @@
1
- # Cli extension
2
-
3
- The `@qodalis/cli-speed-test` package is a CLI extension designed to provide utilities for measuring network speed
4
-
5
- # Installation
6
-
7
- ```bash
8
- packages add @qodalis/cli-speed-test
9
- ```
10
-
11
- # Usage
12
-
13
- ```bash
14
- speed-test run
15
- ```
16
-
17
- This command downloads and registers the extension for use within the CLI environment.
@@ -1,19 +0,0 @@
1
- import { NgModule } from '@angular/core';
2
- import { resolveCommandProcessorProvider } from '@qodalis/angular-cli';
3
- import { CliSpeedTestCommandProcessor } from './processors/cli-speed-test-command-processor';
4
- import * as i0 from "@angular/core";
5
- export class CliSpeedTestModule {
6
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CliSpeedTestModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
7
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: CliSpeedTestModule }); }
8
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CliSpeedTestModule, providers: [resolveCommandProcessorProvider(CliSpeedTestCommandProcessor)] }); }
9
- }
10
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CliSpeedTestModule, decorators: [{
11
- type: NgModule,
12
- args: [{
13
- declarations: [],
14
- imports: [],
15
- exports: [],
16
- providers: [resolveCommandProcessorProvider(CliSpeedTestCommandProcessor)],
17
- }]
18
- }] });
19
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLXNwZWVkLXRlc3QubW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvc3BlZWQtdGVzdC9zcmMvbGliL2NsaS1zcGVlZC10ZXN0Lm1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSwrQkFBK0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3ZFLE9BQU8sRUFBRSw0QkFBNEIsRUFBRSxNQUFNLCtDQUErQyxDQUFDOztBQVE3RixNQUFNLE9BQU8sa0JBQWtCOytHQUFsQixrQkFBa0I7Z0hBQWxCLGtCQUFrQjtnSEFBbEIsa0JBQWtCLGFBRmhCLENBQUMsK0JBQStCLENBQUMsNEJBQTRCLENBQUMsQ0FBQzs7NEZBRWpFLGtCQUFrQjtrQkFOOUIsUUFBUTttQkFBQztvQkFDTixZQUFZLEVBQUUsRUFBRTtvQkFDaEIsT0FBTyxFQUFFLEVBQUU7b0JBQ1gsT0FBTyxFQUFFLEVBQUU7b0JBQ1gsU0FBUyxFQUFFLENBQUMsK0JBQStCLENBQUMsNEJBQTRCLENBQUMsQ0FBQztpQkFDN0UiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBOZ01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgcmVzb2x2ZUNvbW1hbmRQcm9jZXNzb3JQcm92aWRlciB9IGZyb20gJ0Bxb2RhbGlzL2FuZ3VsYXItY2xpJztcbmltcG9ydCB7IENsaVNwZWVkVGVzdENvbW1hbmRQcm9jZXNzb3IgfSBmcm9tICcuL3Byb2Nlc3NvcnMvY2xpLXNwZWVkLXRlc3QtY29tbWFuZC1wcm9jZXNzb3InO1xuXG5ATmdNb2R1bGUoe1xuICAgIGRlY2xhcmF0aW9uczogW10sXG4gICAgaW1wb3J0czogW10sXG4gICAgZXhwb3J0czogW10sXG4gICAgcHJvdmlkZXJzOiBbcmVzb2x2ZUNvbW1hbmRQcm9jZXNzb3JQcm92aWRlcihDbGlTcGVlZFRlc3RDb21tYW5kUHJvY2Vzc29yKV0sXG59KVxuZXhwb3J0IGNsYXNzIENsaVNwZWVkVGVzdE1vZHVsZSB7fVxuIl19
@@ -1,167 +0,0 @@
1
- import { CliForegroundColor, DefaultLibraryAuthor, } from '@qodalis/cli-core';
2
- import axios from 'axios';
3
- import { LIBRARY_VERSION } from '../version';
4
- export class CliSpeedTestCommandProcessor {
5
- constructor() {
6
- this.command = 'speed-test';
7
- this.description = 'Run an internet speed test';
8
- this.author = DefaultLibraryAuthor;
9
- this.processors = [];
10
- this.version = LIBRARY_VERSION;
11
- this.metadata = {
12
- icon: '🚀',
13
- };
14
- this.processors = [
15
- {
16
- command: 'run',
17
- description: 'Run the internet speed test',
18
- parameters: [
19
- {
20
- name: 'download-url',
21
- description: 'URL to download the file',
22
- type: 'string',
23
- required: false,
24
- },
25
- {
26
- name: 'upload-url',
27
- description: 'URL to upload the file',
28
- type: 'string',
29
- required: false,
30
- },
31
- ],
32
- processCommand: async (command, context) => {
33
- const source = axios.CancelToken.source();
34
- const subscription = context.onAbort.subscribe(() => {
35
- source.cancel('Speed test aborted by user');
36
- subscription.unsubscribe();
37
- });
38
- new Promise(async (resolve, reject) => {
39
- context.writer.writeInfo('Starting live speed test...');
40
- const downloadUrl = command.args['download-url'] ||
41
- 'https://proxy.qodalis.com/proxy/https/nbg1-speed.hetzner.com/100MB.bin';
42
- const uploadUrl = command.args['upload-url'] ||
43
- 'https://httpbin.org/post';
44
- try {
45
- await this.runDownloadSpeedTest(downloadUrl, context, source.token);
46
- await this.runUploadSpeedTest(uploadUrl, context, source);
47
- context.writer.writeInfo('Speed test completed');
48
- resolve();
49
- }
50
- catch (error) {
51
- context.writer.writeError(`Speed test failed: ${error?.toString()}`);
52
- reject(error);
53
- }
54
- subscription.unsubscribe();
55
- context.showPrompt();
56
- });
57
- },
58
- },
59
- ];
60
- }
61
- async processCommand(command, context) {
62
- await context.executor.showHelp(command, context);
63
- }
64
- writeDescription(context) {
65
- const { writer } = context;
66
- writer.writeln(this.description);
67
- writer.writeln();
68
- writer.writeln('📋 Usage:');
69
- writer.writeln(` ${writer.wrapInColor('speed-test run', CliForegroundColor.Cyan)} Run download & upload test`);
70
- writer.writeln(` ${writer.wrapInColor('speed-test run --download-url=<url>', CliForegroundColor.Cyan)} Custom download URL`);
71
- writer.writeln(` ${writer.wrapInColor('speed-test run --upload-url=<url>', CliForegroundColor.Cyan)} Custom upload URL`);
72
- writer.writeln();
73
- writer.writeln(`💡 Press ${writer.wrapInColor('Ctrl+C', CliForegroundColor.Yellow)} to abort the test`);
74
- }
75
- /**
76
- * Run the download speed test with live updates.
77
- * @param context CLI execution context.
78
- */
79
- async runDownloadSpeedTest(url, context, cancelToken) {
80
- const startTime = performance.now();
81
- let previousTime = startTime;
82
- let previousLoaded = 0;
83
- await axios.get(url, {
84
- responseType: 'arraybuffer',
85
- cancelToken: cancelToken,
86
- headers: {
87
- Origin: null,
88
- },
89
- onDownloadProgress: (progressEvent) => {
90
- if (!!cancelToken.reason) {
91
- throw new Error('Speed test aborted by user');
92
- }
93
- const currentTime = performance.now();
94
- const elapsedTime = (currentTime - previousTime) / 1000;
95
- const bytesSinceLastUpdate = progressEvent.loaded - previousLoaded;
96
- if (elapsedTime > 0) {
97
- const speedInBps = bytesSinceLastUpdate / elapsedTime; // Bytes per second
98
- const speedInMbps = (speedInBps * 8) / (1024 * 1024); // Convert to Mbps
99
- context.writer.writeln(`Download Speed: ${speedInMbps.toFixed(2)} Mbps (Progress: ${((progressEvent.loaded / progressEvent.total) *
100
- 100).toFixed(2)}%)`);
101
- }
102
- // Update previous values
103
- previousTime = currentTime;
104
- previousLoaded = progressEvent.loaded;
105
- },
106
- });
107
- const endTime = performance.now();
108
- const totalTime = (endTime - startTime) / 1000;
109
- context.writer.writeSuccess(`Download test completed in ${totalTime.toFixed(2)} seconds`);
110
- }
111
- /**
112
- * Run the upload speed test with live updates.
113
- * @param context CLI execution context.
114
- */
115
- async runUploadSpeedTest(url, context, source) {
116
- const testData = new Uint8Array(20 * 1024 * 1024); // 20 MB of random data
117
- testData.fill(0);
118
- const startTime = performance.now();
119
- let previousTime = startTime;
120
- let previousUploaded = 0;
121
- let uploadComplete = false;
122
- try {
123
- await axios.post(url, testData, {
124
- headers: { 'Content-Type': 'application/octet-stream' },
125
- cancelToken: source.token,
126
- responseType: 'stream',
127
- onUploadProgress: (progressEvent) => {
128
- if (!!source.token.reason) {
129
- throw new Error('Speed test aborted by user');
130
- }
131
- const currentTime = performance.now();
132
- const elapsedTime = (currentTime - previousTime) / 1000; // Time since last update
133
- const bytesSinceLastUpdate = progressEvent.loaded - previousUploaded;
134
- if (elapsedTime > 0) {
135
- const speedInBps = bytesSinceLastUpdate / elapsedTime; // Bytes per second
136
- const speedInMbps = (speedInBps * 8) / (1024 * 1024); // Convert to Mbps
137
- context.writer.writeln(`Upload Speed: ${speedInMbps.toFixed(2)} Mbps (Progress: ${((progressEvent.loaded / progressEvent.total) *
138
- 100).toFixed(2)}%)`);
139
- }
140
- // Update previous values
141
- previousTime = currentTime;
142
- previousUploaded = progressEvent.loaded;
143
- if (progressEvent.loaded >= progressEvent.total) {
144
- uploadComplete = true;
145
- source.cancel('Upload test completed');
146
- }
147
- },
148
- });
149
- }
150
- catch (e) {
151
- if (axios.isCancel(e)) {
152
- if (!uploadComplete) {
153
- context.writer.writeError('Upload test aborted by user');
154
- }
155
- else {
156
- const endTime = performance.now();
157
- const totalTime = (endTime - startTime) / 1000;
158
- context.writer.writeSuccess(`Upload test completed in ${totalTime.toFixed(2)} seconds`);
159
- }
160
- }
161
- else {
162
- throw e;
163
- }
164
- }
165
- }
166
- }
167
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLXNwZWVkLXRlc3QtY29tbWFuZC1wcm9jZXNzb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9zcGVlZC10ZXN0L3NyYy9saWIvcHJvY2Vzc29ycy9jbGktc3BlZWQtdGVzdC1jb21tYW5kLXByb2Nlc3Nvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0gsa0JBQWtCLEVBRWxCLG9CQUFvQixHQUN2QixNQUFNLG1CQUFtQixDQUFDO0FBTTNCLE9BQU8sS0FBeUMsTUFBTSxPQUFPLENBQUM7QUFDOUQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUU3QyxNQUFNLE9BQU8sNEJBQTRCO0lBZXJDO1FBZEEsWUFBTyxHQUFHLFlBQVksQ0FBQztRQUV2QixnQkFBVyxHQUFHLDRCQUE0QixDQUFDO1FBRTNDLFdBQU0sR0FBRyxvQkFBb0IsQ0FBQztRQUU5QixlQUFVLEdBQXdDLEVBQUUsQ0FBQztRQUVyRCxZQUFPLEdBQUcsZUFBZSxDQUFDO1FBRTFCLGFBQVEsR0FBc0M7WUFDMUMsSUFBSSxFQUFFLElBQUk7U0FDYixDQUFDO1FBR0UsSUFBSSxDQUFDLFVBQVUsR0FBRztZQUNkO2dCQUNJLE9BQU8sRUFBRSxLQUFLO2dCQUNkLFdBQVcsRUFBRSw2QkFBNkI7Z0JBQzFDLFVBQVUsRUFBRTtvQkFDUjt3QkFDSSxJQUFJLEVBQUUsY0FBYzt3QkFDcEIsV0FBVyxFQUFFLDBCQUEwQjt3QkFDdkMsSUFBSSxFQUFFLFFBQVE7d0JBQ2QsUUFBUSxFQUFFLEtBQUs7cUJBQ2xCO29CQUNEO3dCQUNJLElBQUksRUFBRSxZQUFZO3dCQUNsQixXQUFXLEVBQUUsd0JBQXdCO3dCQUNyQyxJQUFJLEVBQUUsUUFBUTt3QkFDZCxRQUFRLEVBQUUsS0FBSztxQkFDbEI7aUJBQ0o7Z0JBQ0QsY0FBYyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLEVBQUU7b0JBQ3ZD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QkFDbkIsSUFBSSxDQUFDLGNBQWMsRUFBRTtvQkFDakIsT0FBTyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsNkJBQTZCLENBQUMsQ0FBQztpQkFDNUQ7cUJBQU07b0JBQ0gsTUFBTSxPQUFPLEdBQUcsV0FBVyxDQUFDLEdBQUcsRUFBRSxDQUFDO29CQUNsQyxNQUFNLFNBQVMsR0FBRyxDQUFDLE9BQU8sR0FBRyxTQUFTLENBQUMsR0FBRyxJQUFJLENBQUM7b0JBQy9DLE9BQU8sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUN2Qiw0QkFBNEIsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUM3RCxDQUFDO2lCQUNMO2FBQ0o7aUJBQU07Z0JBQ0gsTUFBTSxDQUFDLENBQUM7YUFDWDtTQUNKO0lBQ0wsQ0FBQztDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgICBDbGlGb3JlZ3JvdW5kQ29sb3IsXG4gICAgQ2xpUHJvY2Vzc29yTWV0YWRhdGEsXG4gICAgRGVmYXVsdExpYnJhcnlBdXRob3IsXG59IGZyb20gJ0Bxb2RhbGlzL2NsaS1jb3JlJztcbmltcG9ydCB7XG4gICAgQ2xpUHJvY2Vzc0NvbW1hbmQsXG4gICAgSUNsaUNvbW1hbmRQcm9jZXNzb3IsXG4gICAgSUNsaUV4ZWN1dGlvbkNvbnRleHQsXG59IGZyb20gJ0Bxb2RhbGlzL2NsaS1jb3JlJztcbmltcG9ydCBheGlvcywgeyBDYW5jZWxUb2tlbiwgQ2FuY2VsVG9rZW5Tb3VyY2UgfSBmcm9tICdheGlvcyc7XG5pbXBvcnQgeyBMSUJSQVJZX1ZFUlNJT04gfSBmcm9tICcuLi92ZXJzaW9uJztcblxuZXhwb3J0IGNsYXNzIENsaVNwZWVkVGVzdENvbW1hbmRQcm9jZXNzb3IgaW1wbGVtZW50cyBJQ2xpQ29tbWFuZFByb2Nlc3NvciB7XG4gICAgY29tbWFuZCA9ICdzcGVlZC10ZXN0JztcblxuICAgIGRlc2NyaXB0aW9uID0gJ1J1biBhbiBpbnRlcm5ldCBzcGVlZCB0ZXN0JztcblxuICAgIGF1dGhvciA9IERlZmF1bHRMaWJyYXJ5QXV0aG9yO1xuXG4gICAgcHJvY2Vzc29ycz86IElDbGlDb21tYW5kUHJvY2Vzc29yW10gfCB1bmRlZmluZWQgPSBbXTtcblxuICAgIHZlcnNpb24gPSBMSUJSQVJZX1ZFUlNJT047XG5cbiAgICBtZXRhZGF0YT86IENsaVByb2Nlc3Nvck1ldGFkYXRhIHwgdW5kZWZpbmVkID0ge1xuICAgICAgICBpY29uOiAn8J+agCcsXG4gICAgfTtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLnByb2Nlc3NvcnMgPSBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgY29tbWFuZDogJ3J1bicsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246ICdSdW4gdGhlIGludGVybmV0IHNwZWVkIHRlc3QnLFxuICAgICAgICAgICAgICAgIHBhcmFtZXRlcnM6IFtcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTogJ2Rvd25sb2FkLXVybCcsXG4gICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogJ1VSTCB0byBkb3dubG9hZCB0aGUgZmlsZScsXG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmVkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTogJ3VwbG9hZC11cmwnLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb246ICdVUkwgdG8gdXBsb2FkIHRoZSBmaWxlJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZWQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgcHJvY2Vzc0NvbW1hbmQ6IGFzeW5jIChjb21tYW5kLCBjb250ZXh0KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHNvdXJjZTogQ2FuY2VsVG9rZW5Tb3VyY2UgPVxuICAgICAgICAgICAgICAgICAgICAgICAgYXhpb3MuQ2FuY2VsVG9rZW4uc291cmNlKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3Vic2NyaXB0aW9uID0gY29udGV4dC5vbkFib3J0LnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2UuY2FuY2VsKCdTcGVlZCB0ZXN0IGFib3J0ZWQgYnkgdXNlcicpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBzdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgbmV3IFByb21pc2U8dm9pZD4oYXN5bmMgKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC53cml0ZXIud3JpdGVJbmZvKCdTdGFydGluZyBsaXZlIHNwZWVkIHRlc3QuLi4nKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZG93bmxvYWRVcmwgPVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1hbmQuYXJnc1snZG93bmxvYWQtdXJsJ10gfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnaHR0cHM6Ly9wcm94eS5xb2RhbGlzLmNvbS9wcm94eS9odHRwcy9uYmcxLXNwZWVkLmhldHpuZXIuY29tLzEwME1CLmJpbic7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHVwbG9hZFVybCA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWFuZC5hcmdzWyd1cGxvYWQtdXJsJ10gfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnaHR0cHM6Ly9odHRwYmluLm9yZy9wb3N0JztcblxuICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnJ1bkRvd25sb2FkU3BlZWRUZXN0KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb3dubG9hZFVybCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlLnRva2VuLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnJ1blVwbG9hZFNwZWVkVGVzdChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBsb2FkVXJsLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRleHQud3JpdGVyLndyaXRlSW5mbygnU3BlZWQgdGVzdCBjb21wbGV0ZWQnKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC53cml0ZXIud3JpdGVFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFNwZWVkIHRlc3QgZmFpbGVkOiAke2Vycm9yPy50b1N0cmluZygpfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0LnNob3dQcm9tcHQoKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgIF07XG4gICAgfVxuXG4gICAgYXN5bmMgcHJvY2Vzc0NvbW1hbmQoXG4gICAgICAgIGNvbW1hbmQ6IENsaVByb2Nlc3NDb21tYW5kLFxuICAgICAgICBjb250ZXh0OiBJQ2xpRXhlY3V0aW9uQ29udGV4dCxcbiAgICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgY29udGV4dC5leGVjdXRvci5zaG93SGVscChjb21tYW5kLCBjb250ZXh0KTtcbiAgICB9XG5cbiAgICB3cml0ZURlc2NyaXB0aW9uKGNvbnRleHQ6IElDbGlFeGVjdXRpb25Db250ZXh0KTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHsgd3JpdGVyIH0gPSBjb250ZXh0O1xuICAgICAgICB3cml0ZXIud3JpdGVsbih0aGlzLmRlc2NyaXB0aW9uKTtcbiAgICAgICAgd3JpdGVyLndyaXRlbG4oKTtcbiAgICAgICAgd3JpdGVyLndyaXRlbG4oJ/Cfk4sgVXNhZ2U6Jyk7XG4gICAgICAgIHdyaXRlci53cml0ZWxuKGAgICR7d3JpdGVyLndyYXBJbkNvbG9yKCdzcGVlZC10ZXN0IHJ1bicsIENsaUZvcmVncm91bmRDb2xvci5DeWFuKX0gICAgICAgICAgICAgICAgICAgICAgICAgIFJ1biBkb3dubG9hZCAmIHVwbG9hZCB0ZXN0YCk7XG4gICAgICAgIHdyaXRlci53cml0ZWxuKGAgICR7d3JpdGVyLndyYXBJbkNvbG9yKCdzcGVlZC10ZXN0IHJ1biAtLWRvd25sb2FkLXVybD08dXJsPicsIENsaUZvcmVncm91bmRDb2xvci5DeWFuKX0gICAgIEN1c3RvbSBkb3dubG9hZCBVUkxgKTtcbiAgICAgICAgd3JpdGVyLndyaXRlbG4oYCAgJHt3cml0ZXIud3JhcEluQ29sb3IoJ3NwZWVkLXRlc3QgcnVuIC0tdXBsb2FkLXVybD08dXJsPicsIENsaUZvcmVncm91bmRDb2xvci5DeWFuKX0gICAgICAgQ3VzdG9tIHVwbG9hZCBVUkxgKTtcbiAgICAgICAgd3JpdGVyLndyaXRlbG4oKTtcbiAgICAgICAgd3JpdGVyLndyaXRlbG4oYPCfkqEgUHJlc3MgJHt3cml0ZXIud3JhcEluQ29sb3IoJ0N0cmwrQycsIENsaUZvcmVncm91bmRDb2xvci5ZZWxsb3cpfSB0byBhYm9ydCB0aGUgdGVzdGApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJ1biB0aGUgZG93bmxvYWQgc3BlZWQgdGVzdCB3aXRoIGxpdmUgdXBkYXRlcy5cbiAgICAgKiBAcGFyYW0gY29udGV4dCBDTEkgZXhlY3V0aW9uIGNvbnRleHQuXG4gICAgICovXG4gICAgcHJpdmF0ZSBhc3luYyBydW5Eb3dubG9hZFNwZWVkVGVzdChcbiAgICAgICAgdXJsOiBzdHJpbmcsXG4gICAgICAgIGNvbnRleHQ6IElDbGlFeGVjdXRpb25Db250ZXh0LFxuICAgICAgICBjYW5jZWxUb2tlbjogQ2FuY2VsVG9rZW4sXG4gICAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHN0YXJ0VGltZSA9IHBlcmZvcm1hbmNlLm5vdygpO1xuICAgICAgICBsZXQgcHJldmlvdXNUaW1lID0gc3RhcnRUaW1lO1xuICAgICAgICBsZXQgcHJldmlvdXNMb2FkZWQgPSAwO1xuXG4gICAgICAgIGF3YWl0IGF4aW9zLmdldCh1cmwsIHtcbiAgICAgICAgICAgIHJlc3BvbnNlVHlwZTogJ2FycmF5YnVmZmVyJyxcbiAgICAgICAgICAgIGNhbmNlbFRva2VuOiBjYW5jZWxUb2tlbixcbiAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICBPcmlnaW46IG51bGwsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25Eb3dubG9hZFByb2dyZXNzOiAocHJvZ3Jlc3NFdmVudCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghIWNhbmNlbFRva2VuLnJlYXNvbikge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NwZWVkIHRlc3QgYWJvcnRlZCBieSB1c2VyJyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgY29uc3QgY3VycmVudFRpbWUgPSBwZXJmb3JtYW5jZS5ub3coKTtcbiAgICAgICAgICAgICAgICBjb25zdCBlbGFwc2VkVGltZSA9IChjdXJyZW50VGltZSAtIHByZXZpb3VzVGltZSkgLyAxMDAwO1xuICAgICAgICAgICAgICAgIGNvbnN0IGJ5dGVzU2luY2VMYXN0VXBkYXRlID1cbiAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3NFdmVudC5sb2FkZWQgLSBwcmV2aW91c0xvYWRlZDtcblxuICAgICAgICAgICAgICAgIGlmIChlbGFwc2VkVGltZSA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3BlZWRJbkJwcyA9IGJ5dGVzU2luY2VMYXN0VXBkYXRlIC8gZWxhcHNlZFRpbWU7IC8vIEJ5dGVzIHBlciBzZWNvbmRcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3BlZWRJbk1icHMgPSAoc3BlZWRJbkJwcyAqIDgpIC8gKDEwMjQgKiAxMDI0KTsgLy8gQ29udmVydCB0byBNYnBzXG4gICAgICAgICAgICAgICAgICAgIGNvbnRleHQud3JpdGVyLndyaXRlbG4oXG4gICAgICAgICAgICAgICAgICAgICAgICBgRG93bmxvYWQgU3BlZWQ6ICR7c3BlZWRJbk1icHMudG9GaXhlZChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAyLFxuICAgICAgICAgICAgICAgICAgICAgICAgKX0gTWJwcyAoUHJvZ3Jlc3M6ICR7KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwcm9ncmVzc0V2ZW50LmxvYWRlZCAvIHByb2dyZXNzRXZlbnQudG90YWwhKSAqXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgMTAwXG4gICAgICAgICAgICAgICAgICAgICAgICApLnRvRml4ZWQoMil9JSlgLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIFVwZGF0ZSBwcmV2aW91cyB2YWx1ZXNcbiAgICAgICAgICAgICAgICBwcmV2aW91c1RpbWUgPSBjdXJyZW50VGltZTtcbiAgICAgICAgICAgICAgICBwcmV2aW91c0xvYWRlZCA9IHByb2dyZXNzRXZlbnQubG9hZGVkO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgZW5kVGltZSA9IHBlcmZvcm1hbmNlLm5vdygpO1xuICAgICAgICBjb25zdCB0b3RhbFRpbWUgPSAoZW5kVGltZSAtIHN0YXJ0VGltZSkgLyAxMDAwO1xuICAgICAgICBjb250ZXh0LndyaXRlci53cml0ZVN1Y2Nlc3MoXG4gICAgICAgICAgICBgRG93bmxvYWQgdGVzdCBjb21wbGV0ZWQgaW4gJHt0b3RhbFRpbWUudG9GaXhlZCgyKX0gc2Vjb25kc2AsXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUnVuIHRoZSB1cGxvYWQgc3BlZWQgdGVzdCB3aXRoIGxpdmUgdXBkYXRlcy5cbiAgICAgKiBAcGFyYW0gY29udGV4dCBDTEkgZXhlY3V0aW9uIGNvbnRleHQuXG4gICAgICovXG4gICAgcHJpdmF0ZSBhc3luYyBydW5VcGxvYWRTcGVlZFRlc3QoXG4gICAgICAgIHVybDogc3RyaW5nLFxuICAgICAgICBjb250ZXh0OiBJQ2xpRXhlY3V0aW9uQ29udGV4dCxcbiAgICAgICAgc291cmNlOiBDYW5jZWxUb2tlblNvdXJjZSxcbiAgICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgdGVzdERhdGEgPSBuZXcgVWludDhBcnJheSgyMCAqIDEwMjQgKiAxMDI0KTsgLy8gMjAgTUIgb2YgcmFuZG9tIGRhdGFcbiAgICAgICAgdGVzdERhdGEuZmlsbCgwKTtcbiAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gcGVyZm9ybWFuY2Uubm93KCk7XG4gICAgICAgIGxldCBwcmV2aW91c1RpbWUgPSBzdGFydFRpbWU7XG4gICAgICAgIGxldCBwcmV2aW91c1VwbG9hZGVkID0gMDtcblxuICAgICAgICBsZXQgdXBsb2FkQ29tcGxldGUgPSBmYWxzZTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgYXhpb3MucG9zdCh1cmwsIHRlc3REYXRhLCB7XG4gICAgICAgICAgICAgICAgaGVhZGVyczogeyAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL29jdGV0LXN0cmVhbScgfSxcbiAgICAgICAgICAgICAgICBjYW5jZWxUb2tlbjogc291cmNlLnRva2VuLFxuICAgICAgICAgICAgICAgIHJlc3BvbnNlVHlwZTogJ3N0cmVhbScsXG4gICAgICAgICAgICAgICAgb25VcGxvYWRQcm9ncmVzczogKHByb2dyZXNzRXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCEhc291cmNlLnRva2VuLnJlYXNvbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTcGVlZCB0ZXN0IGFib3J0ZWQgYnkgdXNlcicpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgY3VycmVudFRpbWUgPSBwZXJmb3JtYW5jZS5ub3coKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZWxhcHNlZFRpbWUgPSAoY3VycmVudFRpbWUgLSBwcmV2aW91c1RpbWUpIC8gMTAwMDsgLy8gVGltZSBzaW5jZSBsYXN0IHVwZGF0ZVxuICAgICAgICAgICAgICAgICAgICBjb25zdCBieXRlc1NpbmNlTGFzdFVwZGF0ZSA9XG4gICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzc0V2ZW50LmxvYWRlZCAtIHByZXZpb3VzVXBsb2FkZWQ7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGVsYXBzZWRUaW1lID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3BlZWRJbkJwcyA9IGJ5dGVzU2luY2VMYXN0VXBkYXRlIC8gZWxhcHNlZFRpbWU7IC8vIEJ5dGVzIHBlciBzZWNvbmRcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHNwZWVkSW5NYnBzID0gKHNwZWVkSW5CcHMgKiA4KSAvICgxMDI0ICogMTAyNCk7IC8vIENvbnZlcnQgdG8gTWJwc1xuICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC53cml0ZXIud3JpdGVsbihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBgVXBsb2FkIFNwZWVkOiAke3NwZWVkSW5NYnBzLnRvRml4ZWQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKX0gTWJwcyAoUHJvZ3Jlc3M6ICR7KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocHJvZ3Jlc3NFdmVudC5sb2FkZWQgLyBwcm9ncmVzc0V2ZW50LnRvdGFsISkgKlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxMDBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLnRvRml4ZWQoMil9JSlgLFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIFVwZGF0ZSBwcmV2aW91cyB2YWx1ZXNcbiAgICAgICAgICAgICAgICAgICAgcHJldmlvdXNUaW1lID0gY3VycmVudFRpbWU7XG4gICAgICAgICAgICAgICAgICAgIHByZXZpb3VzVXBsb2FkZWQgPSBwcm9ncmVzc0V2ZW50LmxvYWRlZDtcblxuICAgICAgICAgICAgICAgICAgICBpZiAocHJvZ3Jlc3NFdmVudC5sb2FkZWQgPj0gcHJvZ3Jlc3NFdmVudC50b3RhbCEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHVwbG9hZENvbXBsZXRlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZS5jYW5jZWwoJ1VwbG9hZCB0ZXN0IGNvbXBsZXRlZCcpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBpZiAoYXhpb3MuaXNDYW5jZWwoZSkpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXVwbG9hZENvbXBsZXRlKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRleHQud3JpdGVyLndyaXRlRXJyb3IoJ1VwbG9hZCB0ZXN0IGFib3J0ZWQgYnkgdXNlcicpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVuZFRpbWUgPSBwZXJmb3JtYW5jZS5ub3coKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdG90YWxUaW1lID0gKGVuZFRpbWUgLSBzdGFydFRpbWUpIC8gMTAwMDtcbiAgICAgICAgICAgICAgICAgICAgY29udGV4dC53cml0ZXIud3JpdGVTdWNjZXNzKFxuICAgICAgICAgICAgICAgICAgICAgICAgYFVwbG9hZCB0ZXN0IGNvbXBsZXRlZCBpbiAke3RvdGFsVGltZS50b0ZpeGVkKDIpfSBzZWNvbmRzYCxcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG4iXX0=
@@ -1,3 +0,0 @@
1
- // Automatically generated during build
2
- export const LIBRARY_VERSION = '0.0.3';
3
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3NwZWVkLXRlc3Qvc3JjL2xpYi92ZXJzaW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLHVDQUF1QztBQUN2QyxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsT0FBTyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiXG4vLyBBdXRvbWF0aWNhbGx5IGdlbmVyYXRlZCBkdXJpbmcgYnVpbGRcbmV4cG9ydCBjb25zdCBMSUJSQVJZX1ZFUlNJT04gPSAnMC4wLjMnO1xuICAiXX0=
@@ -1,6 +0,0 @@
1
- /*
2
- * Public API Surface of speed-test
3
- */
4
- export * from './lib/cli-speed-test.module';
5
- export * from './lib/processors/cli-speed-test-command-processor';
6
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL3NwZWVkLXRlc3Qvc3JjL3B1YmxpYy1hcGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLDZCQUE2QixDQUFDO0FBRTVDLGNBQWMsbURBQW1ELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogUHVibGljIEFQSSBTdXJmYWNlIG9mIHNwZWVkLXRlc3RcbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2xpYi9jbGktc3BlZWQtdGVzdC5tb2R1bGUnO1xuXG5leHBvcnQgKiBmcm9tICcuL2xpYi9wcm9jZXNzb3JzL2NsaS1zcGVlZC10ZXN0LWNvbW1hbmQtcHJvY2Vzc29yJztcbiJdfQ==
@@ -1,5 +0,0 @@
1
- /**
2
- * Generated bundle index. Do not edit.
3
- */
4
- export * from './public-api';
5
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicW9kYWxpcy1jbGktc3BlZWQtdGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL3NwZWVkLXRlc3Qvc3JjL3FvZGFsaXMtY2xpLXNwZWVkLXRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLGNBQWMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9wdWJsaWMtYXBpJztcbiJdfQ==
@@ -1,198 +0,0 @@
1
- import * as i0 from '@angular/core';
2
- import { NgModule } from '@angular/core';
3
- import { resolveCommandProcessorProvider } from '@qodalis/angular-cli';
4
- import { DefaultLibraryAuthor, CliForegroundColor } from '@qodalis/cli-core';
5
- import axios from 'axios';
6
-
7
- // Automatically generated during build
8
- const LIBRARY_VERSION = '0.0.3';
9
-
10
- class CliSpeedTestCommandProcessor {
11
- constructor() {
12
- this.command = 'speed-test';
13
- this.description = 'Run an internet speed test';
14
- this.author = DefaultLibraryAuthor;
15
- this.processors = [];
16
- this.version = LIBRARY_VERSION;
17
- this.metadata = {
18
- icon: '🚀',
19
- };
20
- this.processors = [
21
- {
22
- command: 'run',
23
- description: 'Run the internet speed test',
24
- parameters: [
25
- {
26
- name: 'download-url',
27
- description: 'URL to download the file',
28
- type: 'string',
29
- required: false,
30
- },
31
- {
32
- name: 'upload-url',
33
- description: 'URL to upload the file',
34
- type: 'string',
35
- required: false,
36
- },
37
- ],
38
- processCommand: async (command, context) => {
39
- const source = axios.CancelToken.source();
40
- const subscription = context.onAbort.subscribe(() => {
41
- source.cancel('Speed test aborted by user');
42
- subscription.unsubscribe();
43
- });
44
- new Promise(async (resolve, reject) => {
45
- context.writer.writeInfo('Starting live speed test...');
46
- const downloadUrl = command.args['download-url'] ||
47
- 'https://proxy.qodalis.com/proxy/https/nbg1-speed.hetzner.com/100MB.bin';
48
- const uploadUrl = command.args['upload-url'] ||
49
- 'https://httpbin.org/post';
50
- try {
51
- await this.runDownloadSpeedTest(downloadUrl, context, source.token);
52
- await this.runUploadSpeedTest(uploadUrl, context, source);
53
- context.writer.writeInfo('Speed test completed');
54
- resolve();
55
- }
56
- catch (error) {
57
- context.writer.writeError(`Speed test failed: ${error?.toString()}`);
58
- reject(error);
59
- }
60
- subscription.unsubscribe();
61
- context.showPrompt();
62
- });
63
- },
64
- },
65
- ];
66
- }
67
- async processCommand(command, context) {
68
- await context.executor.showHelp(command, context);
69
- }
70
- writeDescription(context) {
71
- const { writer } = context;
72
- writer.writeln(this.description);
73
- writer.writeln();
74
- writer.writeln('📋 Usage:');
75
- writer.writeln(` ${writer.wrapInColor('speed-test run', CliForegroundColor.Cyan)} Run download & upload test`);
76
- writer.writeln(` ${writer.wrapInColor('speed-test run --download-url=<url>', CliForegroundColor.Cyan)} Custom download URL`);
77
- writer.writeln(` ${writer.wrapInColor('speed-test run --upload-url=<url>', CliForegroundColor.Cyan)} Custom upload URL`);
78
- writer.writeln();
79
- writer.writeln(`💡 Press ${writer.wrapInColor('Ctrl+C', CliForegroundColor.Yellow)} to abort the test`);
80
- }
81
- /**
82
- * Run the download speed test with live updates.
83
- * @param context CLI execution context.
84
- */
85
- async runDownloadSpeedTest(url, context, cancelToken) {
86
- const startTime = performance.now();
87
- let previousTime = startTime;
88
- let previousLoaded = 0;
89
- await axios.get(url, {
90
- responseType: 'arraybuffer',
91
- cancelToken: cancelToken,
92
- headers: {
93
- Origin: null,
94
- },
95
- onDownloadProgress: (progressEvent) => {
96
- if (!!cancelToken.reason) {
97
- throw new Error('Speed test aborted by user');
98
- }
99
- const currentTime = performance.now();
100
- const elapsedTime = (currentTime - previousTime) / 1000;
101
- const bytesSinceLastUpdate = progressEvent.loaded - previousLoaded;
102
- if (elapsedTime > 0) {
103
- const speedInBps = bytesSinceLastUpdate / elapsedTime; // Bytes per second
104
- const speedInMbps = (speedInBps * 8) / (1024 * 1024); // Convert to Mbps
105
- context.writer.writeln(`Download Speed: ${speedInMbps.toFixed(2)} Mbps (Progress: ${((progressEvent.loaded / progressEvent.total) *
106
- 100).toFixed(2)}%)`);
107
- }
108
- // Update previous values
109
- previousTime = currentTime;
110
- previousLoaded = progressEvent.loaded;
111
- },
112
- });
113
- const endTime = performance.now();
114
- const totalTime = (endTime - startTime) / 1000;
115
- context.writer.writeSuccess(`Download test completed in ${totalTime.toFixed(2)} seconds`);
116
- }
117
- /**
118
- * Run the upload speed test with live updates.
119
- * @param context CLI execution context.
120
- */
121
- async runUploadSpeedTest(url, context, source) {
122
- const testData = new Uint8Array(20 * 1024 * 1024); // 20 MB of random data
123
- testData.fill(0);
124
- const startTime = performance.now();
125
- let previousTime = startTime;
126
- let previousUploaded = 0;
127
- let uploadComplete = false;
128
- try {
129
- await axios.post(url, testData, {
130
- headers: { 'Content-Type': 'application/octet-stream' },
131
- cancelToken: source.token,
132
- responseType: 'stream',
133
- onUploadProgress: (progressEvent) => {
134
- if (!!source.token.reason) {
135
- throw new Error('Speed test aborted by user');
136
- }
137
- const currentTime = performance.now();
138
- const elapsedTime = (currentTime - previousTime) / 1000; // Time since last update
139
- const bytesSinceLastUpdate = progressEvent.loaded - previousUploaded;
140
- if (elapsedTime > 0) {
141
- const speedInBps = bytesSinceLastUpdate / elapsedTime; // Bytes per second
142
- const speedInMbps = (speedInBps * 8) / (1024 * 1024); // Convert to Mbps
143
- context.writer.writeln(`Upload Speed: ${speedInMbps.toFixed(2)} Mbps (Progress: ${((progressEvent.loaded / progressEvent.total) *
144
- 100).toFixed(2)}%)`);
145
- }
146
- // Update previous values
147
- previousTime = currentTime;
148
- previousUploaded = progressEvent.loaded;
149
- if (progressEvent.loaded >= progressEvent.total) {
150
- uploadComplete = true;
151
- source.cancel('Upload test completed');
152
- }
153
- },
154
- });
155
- }
156
- catch (e) {
157
- if (axios.isCancel(e)) {
158
- if (!uploadComplete) {
159
- context.writer.writeError('Upload test aborted by user');
160
- }
161
- else {
162
- const endTime = performance.now();
163
- const totalTime = (endTime - startTime) / 1000;
164
- context.writer.writeSuccess(`Upload test completed in ${totalTime.toFixed(2)} seconds`);
165
- }
166
- }
167
- else {
168
- throw e;
169
- }
170
- }
171
- }
172
- }
173
-
174
- class CliSpeedTestModule {
175
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CliSpeedTestModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
176
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: CliSpeedTestModule }); }
177
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CliSpeedTestModule, providers: [resolveCommandProcessorProvider(CliSpeedTestCommandProcessor)] }); }
178
- }
179
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CliSpeedTestModule, decorators: [{
180
- type: NgModule,
181
- args: [{
182
- declarations: [],
183
- imports: [],
184
- exports: [],
185
- providers: [resolveCommandProcessorProvider(CliSpeedTestCommandProcessor)],
186
- }]
187
- }] });
188
-
189
- /*
190
- * Public API Surface of speed-test
191
- */
192
-
193
- /**
194
- * Generated bundle index. Do not edit.
195
- */
196
-
197
- export { CliSpeedTestCommandProcessor, CliSpeedTestModule };
198
- //# sourceMappingURL=qodalis-cli-speed-test.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"qodalis-cli-speed-test.mjs","sources":["../../../projects/speed-test/src/lib/version.ts","../../../projects/speed-test/src/lib/processors/cli-speed-test-command-processor.ts","../../../projects/speed-test/src/lib/cli-speed-test.module.ts","../../../projects/speed-test/src/public-api.ts","../../../projects/speed-test/src/qodalis-cli-speed-test.ts"],"sourcesContent":["\n// Automatically generated during build\nexport const LIBRARY_VERSION = '0.0.3';\n ","import {\n CliForegroundColor,\n CliProcessorMetadata,\n DefaultLibraryAuthor,\n} from '@qodalis/cli-core';\nimport {\n CliProcessCommand,\n ICliCommandProcessor,\n ICliExecutionContext,\n} from '@qodalis/cli-core';\nimport axios, { CancelToken, CancelTokenSource } from 'axios';\nimport { LIBRARY_VERSION } from '../version';\n\nexport class CliSpeedTestCommandProcessor implements ICliCommandProcessor {\n command = 'speed-test';\n\n description = 'Run an internet speed test';\n\n author = DefaultLibraryAuthor;\n\n processors?: ICliCommandProcessor[] | undefined = [];\n\n version = LIBRARY_VERSION;\n\n metadata?: CliProcessorMetadata | undefined = {\n icon: '🚀',\n };\n\n constructor() {\n this.processors = [\n {\n command: 'run',\n description: 'Run the internet speed test',\n parameters: [\n {\n name: 'download-url',\n description: 'URL to download the file',\n type: 'string',\n required: false,\n },\n {\n name: 'upload-url',\n description: 'URL to upload the file',\n type: 'string',\n required: false,\n },\n ],\n processCommand: async (command, context) => {\n const source: CancelTokenSource =\n axios.CancelToken.source();\n\n const subscription = context.onAbort.subscribe(() => {\n source.cancel('Speed test aborted by user');\n\n subscription.unsubscribe();\n });\n\n new Promise<void>(async (resolve, reject) => {\n context.writer.writeInfo('Starting live speed test...');\n\n const downloadUrl =\n command.args['download-url'] ||\n 'https://proxy.qodalis.com/proxy/https/nbg1-speed.hetzner.com/100MB.bin';\n\n const uploadUrl =\n command.args['upload-url'] ||\n 'https://httpbin.org/post';\n\n try {\n await this.runDownloadSpeedTest(\n downloadUrl,\n context,\n source.token,\n );\n\n await this.runUploadSpeedTest(\n uploadUrl,\n context,\n source,\n );\n\n context.writer.writeInfo('Speed test completed');\n\n resolve();\n } catch (error) {\n context.writer.writeError(\n `Speed test failed: ${error?.toString()}`,\n );\n\n reject(error);\n }\n\n subscription.unsubscribe();\n\n context.showPrompt();\n });\n },\n },\n ];\n }\n\n async processCommand(\n command: CliProcessCommand,\n context: ICliExecutionContext,\n ): Promise<void> {\n await context.executor.showHelp(command, context);\n }\n\n writeDescription(context: ICliExecutionContext): void {\n const { writer } = context;\n writer.writeln(this.description);\n writer.writeln();\n writer.writeln('📋 Usage:');\n writer.writeln(` ${writer.wrapInColor('speed-test run', CliForegroundColor.Cyan)} Run download & upload test`);\n writer.writeln(` ${writer.wrapInColor('speed-test run --download-url=<url>', CliForegroundColor.Cyan)} Custom download URL`);\n writer.writeln(` ${writer.wrapInColor('speed-test run --upload-url=<url>', CliForegroundColor.Cyan)} Custom upload URL`);\n writer.writeln();\n writer.writeln(`💡 Press ${writer.wrapInColor('Ctrl+C', CliForegroundColor.Yellow)} to abort the test`);\n }\n\n /**\n * Run the download speed test with live updates.\n * @param context CLI execution context.\n */\n private async runDownloadSpeedTest(\n url: string,\n context: ICliExecutionContext,\n cancelToken: CancelToken,\n ): Promise<void> {\n const startTime = performance.now();\n let previousTime = startTime;\n let previousLoaded = 0;\n\n await axios.get(url, {\n responseType: 'arraybuffer',\n cancelToken: cancelToken,\n headers: {\n Origin: null,\n },\n onDownloadProgress: (progressEvent) => {\n if (!!cancelToken.reason) {\n throw new Error('Speed test aborted by user');\n }\n\n const currentTime = performance.now();\n const elapsedTime = (currentTime - previousTime) / 1000;\n const bytesSinceLastUpdate =\n progressEvent.loaded - previousLoaded;\n\n if (elapsedTime > 0) {\n const speedInBps = bytesSinceLastUpdate / elapsedTime; // Bytes per second\n const speedInMbps = (speedInBps * 8) / (1024 * 1024); // Convert to Mbps\n context.writer.writeln(\n `Download Speed: ${speedInMbps.toFixed(\n 2,\n )} Mbps (Progress: ${(\n (progressEvent.loaded / progressEvent.total!) *\n 100\n ).toFixed(2)}%)`,\n );\n }\n\n // Update previous values\n previousTime = currentTime;\n previousLoaded = progressEvent.loaded;\n },\n });\n\n const endTime = performance.now();\n const totalTime = (endTime - startTime) / 1000;\n context.writer.writeSuccess(\n `Download test completed in ${totalTime.toFixed(2)} seconds`,\n );\n }\n\n /**\n * Run the upload speed test with live updates.\n * @param context CLI execution context.\n */\n private async runUploadSpeedTest(\n url: string,\n context: ICliExecutionContext,\n source: CancelTokenSource,\n ): Promise<void> {\n const testData = new Uint8Array(20 * 1024 * 1024); // 20 MB of random data\n testData.fill(0);\n const startTime = performance.now();\n let previousTime = startTime;\n let previousUploaded = 0;\n\n let uploadComplete = false;\n\n try {\n await axios.post(url, testData, {\n headers: { 'Content-Type': 'application/octet-stream' },\n cancelToken: source.token,\n responseType: 'stream',\n onUploadProgress: (progressEvent) => {\n if (!!source.token.reason) {\n throw new Error('Speed test aborted by user');\n }\n\n const currentTime = performance.now();\n const elapsedTime = (currentTime - previousTime) / 1000; // Time since last update\n const bytesSinceLastUpdate =\n progressEvent.loaded - previousUploaded;\n\n if (elapsedTime > 0) {\n const speedInBps = bytesSinceLastUpdate / elapsedTime; // Bytes per second\n const speedInMbps = (speedInBps * 8) / (1024 * 1024); // Convert to Mbps\n context.writer.writeln(\n `Upload Speed: ${speedInMbps.toFixed(\n 2,\n )} Mbps (Progress: ${(\n (progressEvent.loaded / progressEvent.total!) *\n 100\n ).toFixed(2)}%)`,\n );\n }\n\n // Update previous values\n previousTime = currentTime;\n previousUploaded = progressEvent.loaded;\n\n if (progressEvent.loaded >= progressEvent.total!) {\n uploadComplete = true;\n source.cancel('Upload test completed');\n }\n },\n });\n } catch (e) {\n if (axios.isCancel(e)) {\n if (!uploadComplete) {\n context.writer.writeError('Upload test aborted by user');\n } else {\n const endTime = performance.now();\n const totalTime = (endTime - startTime) / 1000;\n context.writer.writeSuccess(\n `Upload test completed in ${totalTime.toFixed(2)} seconds`,\n );\n }\n } else {\n throw e;\n }\n }\n }\n}\n","import { NgModule } from '@angular/core';\nimport { resolveCommandProcessorProvider } from '@qodalis/angular-cli';\nimport { CliSpeedTestCommandProcessor } from './processors/cli-speed-test-command-processor';\n\n@NgModule({\n declarations: [],\n imports: [],\n exports: [],\n providers: [resolveCommandProcessorProvider(CliSpeedTestCommandProcessor)],\n})\nexport class CliSpeedTestModule {}\n","/*\n * Public API Surface of speed-test\n */\n\nexport * from './lib/cli-speed-test.module';\n\nexport * from './lib/processors/cli-speed-test-command-processor';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/index.d.ts DELETED
@@ -1,5 +0,0 @@
1
- /**
2
- * Generated bundle index. Do not edit.
3
- */
4
- /// <amd-module name="@qodalis/cli-speed-test" />
5
- export * from './public-api';
@@ -1,6 +0,0 @@
1
- import * as i0 from "@angular/core";
2
- export declare class CliSpeedTestModule {
3
- static ɵfac: i0.ɵɵFactoryDeclaration<CliSpeedTestModule, never>;
4
- static ɵmod: i0.ɵɵNgModuleDeclaration<CliSpeedTestModule, never, never, never>;
5
- static ɵinj: i0.ɵɵInjectorDeclaration<CliSpeedTestModule>;
6
- }
@@ -1,23 +0,0 @@
1
- import { CliProcessorMetadata } from '@qodalis/cli-core';
2
- import { CliProcessCommand, ICliCommandProcessor, ICliExecutionContext } from '@qodalis/cli-core';
3
- export declare class CliSpeedTestCommandProcessor implements ICliCommandProcessor {
4
- command: string;
5
- description: string;
6
- author: import("@qodalis/cli-core").ICliCommandAuthor;
7
- processors?: ICliCommandProcessor[] | undefined;
8
- version: string;
9
- metadata?: CliProcessorMetadata | undefined;
10
- constructor();
11
- processCommand(command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
12
- writeDescription(context: ICliExecutionContext): void;
13
- /**
14
- * Run the download speed test with live updates.
15
- * @param context CLI execution context.
16
- */
17
- private runDownloadSpeedTest;
18
- /**
19
- * Run the upload speed test with live updates.
20
- * @param context CLI execution context.
21
- */
22
- private runUploadSpeedTest;
23
- }
package/lib/version.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare const LIBRARY_VERSION = "0.0.3";