SpeedOf.Me API - Angular Integration

Note: Angular requires a build process (TypeScript compilation, bundling). This page shows the source code. See the README for setup instructions.

1. Type Definitions (speedofme.d.ts)

src/types/speedofme.d.ts
interface SpeedTestResult {
    download: number;
    upload: number;
    latency: number;
    jitter: number;
    testServer?: string;
    ip_address?: string;
    hostname?: string;
}

interface SpeedTestProgress {
    testType: 'download' | 'upload';
    currentSpeed: number;
    percentComplete: number;
    passNumber: number;
}

interface SomApi {
    account: string;
    domainName: string;
    config: {
        sustainTime: number;
        testServerEnabled: boolean;
        userInfoEnabled: boolean;
        latencyTestEnabled: boolean;
        uploadTestEnabled: boolean;
    };
    startTest: () => void;
    onTestCompleted: (result: SpeedTestResult) => void;
    onProgress: (progress: SpeedTestProgress) => void;
    onError: (error: { code: number; message: string }) => void;
}

declare var SomApi: SomApi;

2. Speed Test Service (speed-test.service.ts)

src/app/services/speed-test.service.ts
import { Injectable, NgZone } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

export type TestStatus = 'idle' | 'running' | 'completed' | 'error';

@Injectable({ providedIn: 'root' })
export class SpeedTestService {
    private statusSubject = new BehaviorSubject<TestStatus>('idle');
    private resultSubject = new BehaviorSubject<SpeedTestResult | null>(null);
    private progressSubject = new BehaviorSubject<SpeedTestProgress | null>(null);
    private errorSubject = new BehaviorSubject<{ code: number; message: string } | null>(null);

    status$ = this.statusSubject.asObservable();
    result$ = this.resultSubject.asObservable();
    progress$ = this.progressSubject.asObservable();
    error$ = this.errorSubject.asObservable();

    constructor(private ngZone: NgZone) {
        this.initializeApi();
    }

    private initializeApi(): void {
        // Configure API
        SomApi.account = 'YOUR_API_KEY';
        SomApi.domainName = 'your-domain.com';
        SomApi.config.sustainTime = 4;

        // Set up callbacks with NgZone for change detection
        SomApi.onTestCompleted = (result) => {
            this.ngZone.run(() => {
                this.resultSubject.next(result);
                this.progressSubject.next(null);
                this.statusSubject.next('completed');
            });
        };

        SomApi.onProgress = (progress) => {
            this.ngZone.run(() => {
                this.progressSubject.next(progress);
            });
        };

        SomApi.onError = (error) => {
            this.ngZone.run(() => {
                this.errorSubject.next(error);
                this.statusSubject.next('error');
            });
        };
    }

    startTest(): void {
        this.statusSubject.next('running');
        this.resultSubject.next(null);
        this.errorSubject.next(null);
        SomApi.startTest();
    }
}

3. Speed Test Component (speed-test.component.ts)

src/app/components/speed-test/speed-test.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SpeedTestService } from '../../services/speed-test.service';

@Component({
    selector: 'app-speed-test',
    standalone: true,
    imports: [CommonModule],
    template: `
        <div class="speed-test">
            <button
                (click)="startTest()"
                [disabled]="(status$ | async) === 'running'"
            >
                {{ (status$ | async) === 'running' ? 'Testing...' : 'Start Test' }}
            </button>

            <div *ngIf="progress$ | async as progress" class="progress">
                <p>{{ progress.testType | titlecase }} Test</p>
                <div class="progress-bar">
                    <div [style.width.%]="progress.percentComplete"></div>
                </div>
                <p>{{ progress.currentSpeed.toFixed(2) }} Mbps</p>
            </div>

            <div *ngIf="result$ | async as result" class="results">
                <p>Download: {{ result.download }} Mbps</p>
                <p>Upload: {{ result.upload }} Mbps</p>
                <p>Latency: {{ result.latency }} ms</p>
                <p>Jitter: {{ result.jitter }} ms</p>
            </div>

            <div *ngIf="error$ | async as error" class="error">
                Error {{ error.code }}: {{ error.message }}
            </div>
        </div>
    `
})
export class SpeedTestComponent {
    status$ = this.speedTestService.status$;
    result$ = this.speedTestService.result$;
    progress$ = this.speedTestService.progress$;
    error$ = this.speedTestService.error$;

    constructor(private speedTestService: SpeedTestService) {}

    startTest(): void {
        this.speedTestService.startTest();
    }
}

4. Add Script to index.html

src/index.html
<!DOCTYPE html>
<html>
<head>
    <!-- Add before closing </head> tag -->
    <script src="https://speedof.me/api/api.js"></script>
</head>
<body>
    <app-root></app-root>
</body>
</html>