Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OpenSpeed logo

OpenSpeed

A native desktop internet speed test application supporting two independent measurement protocols: NDT7 (M-Lab) and LibreSpeed (global public servers).
Built with Tauri v2 (Rust backend) and React 19 (TypeScript frontend).

License: AGPL v3 Tauri 2.x Rust 2021 React 19 Cross-platform

🇬🇧 English · 🇮🇹 Italiano

🖥️ No Electron. No browser. A native desktop binary with a Rust async networking core.


English 🇬🇧

Overview 🚀

OpenSpeed measures download/upload throughput and connection quality (ping, jitter, packet loss) using two independent protocols:

  • NDT7 — the open measurement standard from Measurement Lab, used over WebSocket Secure against the nearest M-Lab server worldwide.
  • LibreSpeed — an HTTPS-based protocol (no WebSocket), used against a merged pool of public servers (GARR, an embedded global list, and the official librespeed.org directory).

All network I/O runs asynchronously in Rust (Tokio). The frontend receives real-time updates via Tauri's IPC event system — no polling.

Features ✨

  • Dual-protocol — switch between NDT7 (M-Lab) and LibreSpeed before starting a test.
  • Global Server Browser — a modal to pick a test server manually: 57 countries for NDT7 (queries the M-Lab Locate API with the country's center coordinates), 17 countries for LibreSpeed (merges embedded, GARR, and live librespeed.org sources, pings all candidates concurrently, sorts by latency). Ping color codes: green (< 30 ms), yellow (< 80 ms), red (≥ 80 ms). Manual selection overrides automatic nearest-server discovery for the next test.
  • Real-time analog gauge — animated SVG needle gauge, auto-scaling 25 → 2500 Mbps.
  • Live line chart — download (blue) and upload (green) time series, updated every 250ms.
  • Metrics panel — ping / min RTT, jitter, retransmission rate (NDT7 only, amber warning above 5%), server IP, client IP, server city/country, with Good/Fair/Poor quality indicators and hover tooltips.
  • Network & ISP badge — Ethernet/Wi-Fi detection (via sysinfo), ISP name and country flag resolved from ipinfo.io at startup.
  • Safety controls — see the dedicated section below.

Tech Stack 🧰

Layer Technology Version
Desktop framework Tauri 2.x
Rust edition 2021
Async runtime Tokio 1.x (features = ["full"])
WebSocket tokio-tungstenite 0.24 (native-tls)
HTTP client reqwest 0.12 (json feature)
Random data rand 0.8
System info sysinfo 0.30
Serialization serde + serde_json 1.x
UI framework React 19.x
Language TypeScript ~5.8.3
Bundler Vite 7.x
CSS framework TailwindCSS 4.x (via @tailwindcss/vite plugin — no postcss)
Charts Recharts 3.x

Installation ⚙️

Prerequisites:

  • Rust (stable toolchain)
  • Node.js ≥ 20
  • Tauri v2 system prerequisites for your OS — see tauri.app/start/prerequisites (varies by platform and Tauri release; do not rely on a fixed package list, always check the official page)

The Tauri CLI itself does not need a separate cargo install tauri-cli — it ships as @tauri-apps/cli in devDependencies and is installed automatically by npm install.

git clone <repo-url>
cd OpenSpeed/open_speed
npm install

Usage ▶️

Development mode (hot-reload frontend + Rust rebuild on save):

npm run tauri dev

This starts the Vite dev server on port 1420 (strict — the command fails if the port is occupied) and launches the Tauri window pointed at it.

Production build:

npm run tauri build
# or, equivalently, since @tauri-apps/cli is installed locally:
cargo tauri build

Produces a native installer under src-tauri/target/release/bundle/ (.msi/portable on Windows, .dmg/.app on macOS, .deb/.rpm on Linux, depending on the platform you build on).

Using the app:

  1. Choose a protocol (NDT7 · M-Lab or LibreSpeed) from the selector shown when idle or after a completed test.
  2. Optionally open the Server Browser to pick a country and a specific server manually; otherwise the nearest server is auto-selected.
  3. Start the test. The status line reports the current phase (locating → downloading → uploading → completed), while the gauge, chart, and metrics panel update live.
  4. Wait at least 30 seconds between tests (enforced by the app) before starting a new one.

Protocols 📡

NDT7 — M-Lab 📶

Server discovery:

GET https://locate.measurementlab.net/v2/nearest/ndt/ndt7

Returns the geographically nearest M-Lab servers ranked by latency (or servers near a chosen country's center coordinates, when picked via the Server Browser). OpenSpeed uses the first result, with one fallback to the second on error — no further retries.

Download (15s):

  • Connects via WSS with header Sec-WebSocket-Protocol: net.measurementlab.ndt.v7.
  • The server sends a continuous stream of binary frames; OpenSpeed counts every received byte.
  • speed_mbps = total_bytes × 8 / elapsed_secs / 1_000_000, emitted every 250ms.
  • The server also sends JSON text frames (TCPInfo) with TCP diagnostic data.

Upload (10s):

  • OpenSpeed sends binary frames starting at 8KB, scaling up to 1MB (doubles when bulk_size <= total_sent / 16, faithful to ndt7-client-go). Buffer content is random ASCII letters, regenerated on each resize.
  • Upload speed is server-side, from TCPInfo.BytesReceived × 8 / TCPInfo.ElapsedTime_µs — authoritative per the NDT7 spec.

Absolute timeout: 55s, wrapping the entire locate + download + upload sequence.

LibreSpeed 🌐

Server discovery merges three sources, deduplicated by server id (embedded entries win, preserving curated geo data):

Source Coverage Update
Embedded JSON (global_librespeed_servers.json) 22 servers, 17 countries Bundled with the app
GARR (speedtest.garr.it/servers.json) Italian research/education network Live fetch
Official directory (librespeed.org/backend-servers/servers.php) ~45 public servers Live fetch, 4s timeout

Nearest-server auto-selection uses euclidean distance between the user's geolocation (from ipinfo.io) and each server's lat/lon. Countries without public LibreSpeed servers (AU, BR, CA, FR, SE, NO, PT, ES, …) are simply absent from the list — NDT7 covers these via M-Lab's global infrastructure.

Ping (before the test): 10 consecutive HTTP HEAD requests to <server>/ping.phpmin_rtt_ms + jitter_ms. DNS resolution of the server hostname and a GET to <server>/getIP.php (client IP) run concurrently with ping via tokio::join!.

Download (10s): 3 concurrent HTTP GET streams to <server>/garbage.php?ckSize=10 (10MB each), looping for the duration; bytes counted from streamed chunks, emitted every 250ms.

Upload (8s): 3 concurrent HTTP POST requests, each sending a 2MB random blob, looping for the duration; bytes counted on successful responses, emitted every 250ms.

Absolute timeout: 60s.

Metrics Reference 📊

NDT7 📶

Metric Label in UI Source Description Good Fair Poor
Best Ping min_rtt_ms TCPInfo.MinRTT / 1000 Lowest RTT sample recorded by the server's TCP stack during download ≤20ms ≤80ms >80ms
Avg Ping rtt_ms TCPInfo.RTT / 1000 Most recent smoothed RTT from the server TCP stack ≤30ms ≤100ms >100ms
Jitter jitter_ms mean |RTT[i]-RTT[i-1]| Variation in RTT across all download TCPInfo samples, computed at end of download ≤5ms ≤20ms >20ms
Packet Loss retransmission_rate BytesRetrans / BytesSent × 100 Percentage of bytes the server had to retransmit; >5% triggers an amber warning ≤1% ≤5% >5%
Server IP server_ip ConnectionInfo.Server IP:port of the NDT7 server
Your IP client_ip ConnectionInfo.Client Your public IP:port as seen by the server

All TCPInfo values are in microseconds; OpenSpeed divides by 1000 to display milliseconds. Jitter is preserved across the upload phase via a frontend merge (upload TCPInfo emits jitter_ms: null, and the frontend keeps the value from the download phase).

LibreSpeed 🌐

Metric Label in UI Source Description Good Fair Poor
HTTP Ping min_rtt_ms min of 10 HEAD round-trips Fastest HTTP round-trip to the server; slightly higher than raw TCP ping due to HTTP overhead ≤30ms ≤100ms >100ms
Jitter jitter_ms mean |RTT[i]-RTT[i-1]| across 9 consecutive ping pairs Stability of the HTTP connection ≤5ms ≤20ms >20ms
Server IP server_ip DNS lookup of the server hostname IP of the test server
Your IP client_ip getIpURL JSON response Your public IP as seen by the server

LibreSpeed does not provide packet loss (no TCP counterflow) or an average-ping metric distinct from best ping.

Architecture 🏗️

OpenSpeed/
└── open_speed/
    ├── src/                          ← React 19 frontend
    │   ├── App.tsx                   ← Dashboard, IPC listeners, protocol selector
    │   ├── index.css                 ← Tailwind v4 (@import "tailwindcss")
    │   ├── types/ipc.ts              ← TypeScript interfaces for all IPC payloads
    │   └── components/
    │       ├── SpeedGauge.tsx        ← SVG analog gauge, auto-scaling 25-2500 Mbps
    │       ├── SpeedChart.tsx        ← Recharts line chart (DL=blue, UL=green)
    │       ├── MetricsPanel.tsx      ← Quality-aware metric cards, protocol-specific sets
    │       ├── NetworkBadge.tsx      ← Ethernet/WiFi badge + ISP name + country flag
    │       └── ServerBrowser.tsx     ← Server selection modal (country filter, ping, select)
    └── src-tauri/src/
        ├── lib.rs                    ← Tauri commands, AppState, safety controls
        ├── models.rs                 ← Shared structs (IPC payloads + NDT7 JSON)
        ├── hardware.rs               ← Network interface detection via sysinfo
        ├── assets/
        │   ├── country_coords.json              ← 57 countries with lat/lon (NDT7 browser)
        │   └── global_librespeed_servers.json    ← 22 embedded LibreSpeed servers
        └── network/
            ├── locate.rs             ← M-Lab Locate API → nearest NDT7 servers
            ├── download.rs           ← NDT7 download (15s, binary frame counting)
            ├── upload.rs             ← NDT7 upload (10s, 8KB→1MB scaling)
            └── librespeed/
                ├── servers.rs        ← GARR + live librespeed.org fetch + embedded list
                ├── ping.rs           ← 10× HTTP HEAD → min_ms + jitter_ms
                ├── download.rs       ← 3 concurrent GETs, 10s, 250ms emit
                └── upload.rs         ← 3 concurrent POSTs, 8s, 250ms emit

IPC events (Rust → Frontend):

Event Payload When emitted
test-status { status, message, server, server_city, server_country, server_country_code } Every phase transition
download-speed { speed_mbps, elapsed_ms } Every 250ms during download
upload-speed { speed_mbps, elapsed_ms } Every 250ms during upload
test-metrics { min_rtt_ms, rtt_ms, retransmission_rate, jitter_ms, server_ip, client_ip } On each TCPInfo frame (NDT7) or once after ping (LibreSpeed)

Tauri commands (Frontend → Rust):

Command Returns Notes
start_speed_test(server?) Promise<void> NDT7; optional manual server override; throws on rate-limit or concurrent test
start_librespeed_test(server?, userLat?, userLon?) Promise<void> LibreSpeed; same guards; coordinates enable nearest-server auto-select
get_network_info() Promise<NetworkInfoPayload> Interface type + name
get_isp_info() Promise<IspInfoPayload> Calls ipinfo.io/json once at startup — ISP, country, lat/lon
get_server_list(protocol, countryCode?, userLat?, userLon?) Promise<ServerListItem[]> Powers the Server Browser

Safety Controls 🛡️

Control Value Details
Rate limit 30s between tests Shared across both protocols; the timer starts after the test ends, not at the start
Concurrent-test guard Mutex<bool> Rejects a second invoke() while a test is running
NDT7 absolute timeout 55s Wraps the entire locate + download + upload sequence
LibreSpeed absolute timeout 60s Wraps the entire locate + ping + download + upload sequence
NDT7 download / upload timeout 15s / 10s Hard stop in download.rs / upload.rs
LibreSpeed download / upload timeout 10s / 8s Hard stop in librespeed/download.rs / librespeed/upload.rs
WebSocket handshake timeout 7s Applied on WS connect
NDT7 server fallback Max 1 Falls back to the second Locate API result only; no retry loops
Locate API call Once per test A single get_nearest_servers() call per run_full_test

These controls are considered non-negotiable in this project and must not be weakened.

License & Attribution 📄

OpenSpeed is licensed under the GNU Affero General Public License v3.0 — see LICENSE.

  • NDT7: the protocol implementation is an independent Rust reimplementation, using ndt7-client-go (Apache License 2.0, © Measurement Lab) purely as a protocol reference — no code was copied. Voluntary attribution is recorded in NOTICE and in source comments at the top of network/locate.rs, network/download.rs, and network/upload.rs.
  • LibreSpeed: the client is an original implementation, not derived from librespeed/speedtest-cli (LGPL v3) — no code was copied, only the wire protocol semantics were referenced. See NOTICE for details.
  • Network measurements rely on M-Lab's public NDT7 infrastructure and on GARR / the official LibreSpeed public server directory; neither is bundled or redistributed by this project.

Known Limitations ⚠️

  • link_speed_mbps is always nullsysinfo does not expose link speed (would require the netdev crate).
  • No result history — measurements are not persisted between sessions.
  • LibreSpeed: countries without public servers (AU, BR, CA, FR, SE, NO, PT, ES, …) show an empty list in the Server Browser — use NDT7 for those.

Italiano 🇮🇹

Panoramica 🚀

OpenSpeed misura la velocità di download/upload e la qualità della connessione (ping, jitter, perdita di pacchetti) usando due protocolli indipendenti:

  • NDT7 — lo standard di misurazione aperto di Measurement Lab, usato via WebSocket Secure contro il server M-Lab più vicino a livello mondiale.
  • LibreSpeed — un protocollo basato su HTTPS (nessun WebSocket), usato contro un pool unificato di server pubblici (GARR, una lista globale integrata nell'app e la directory ufficiale librespeed.org).

Tutto l'I/O di rete è asincrono in Rust (Tokio). Il frontend riceve aggiornamenti in tempo reale tramite il sistema di eventi IPC di Tauri — nessun polling.

Funzionalità ✨

  • Doppio protocollo — passa da NDT7 (M-Lab) a LibreSpeed prima di avviare un test.
  • Server Browser globale — una finestra modale per scegliere manualmente il server di test: 57 paesi per NDT7 (interroga la Locate API di M-Lab con le coordinate del centro del paese), 17 paesi per LibreSpeed (unisce le fonti integrata, GARR e librespeed.org, esegue il ping su tutti i candidati in parallelo e ordina per latenza). Codici colore del ping: verde (< 30 ms), giallo (< 80 ms), rosso (≥ 80 ms). La selezione manuale sostituisce la ricerca automatica del server più vicino per il test successivo.
  • Gauge analogico in tempo reale — lancetta SVG animata, scala automatica 25 → 2500 Mbps.
  • Grafico a linee in tempo reale — serie temporali di download (blu) e upload (verde), aggiornate ogni 250ms.
  • Pannello metriche — ping / RTT minimo, jitter, tasso di ritrasmissione (solo NDT7, avviso ambra sopra il 5%), IP del server, IP del client, città/paese del server, con indicatori di qualità Buono/Discreto/Scarso e tooltip al passaggio del mouse.
  • Badge di rete e ISP — rilevamento Ethernet/Wi-Fi (via sysinfo), nome ISP e bandiera del paese risolti da ipinfo.io all'avvio.
  • Controlli di sicurezza — vedi la sezione dedicata più sotto.

Stack Tecnologico 🧰

Livello Tecnologia Versione
Framework desktop Tauri 2.x
Edizione Rust 2021
Runtime asincrono Tokio 1.x (features = ["full"])
WebSocket tokio-tungstenite 0.24 (native-tls)
Client HTTP reqwest 0.12 (feature json)
Dati casuali rand 0.8
Info di sistema sysinfo 0.30
Serializzazione serde + serde_json 1.x
Framework UI React 19.x
Linguaggio TypeScript ~5.8.3
Bundler Vite 7.x
Framework CSS TailwindCSS 4.x (via plugin @tailwindcss/vite — senza postcss)
Grafici Recharts 3.x

Installazione ⚙️

Prerequisiti:

  • Rust (toolchain stable)
  • Node.js ≥ 20
  • Prerequisiti di sistema Tauri v2 per il proprio sistema operativo — vedi tauri.app/start/prerequisites (variano per piattaforma e versione di Tauri; non fare affidamento su un elenco fisso di pacchetti, consultare sempre la pagina ufficiale)

La CLI di Tauri non richiede un cargo install tauri-cli separato — è inclusa come @tauri-apps/cli nelle devDependencies e viene installata automaticamente da npm install.

git clone <repo-url>
cd OpenSpeed/open_speed
npm install

Utilizzo ▶️

Modalità sviluppo (hot-reload del frontend + ricompilazione Rust ad ogni salvataggio):

npm run tauri dev

Questo avvia il server di sviluppo Vite sulla porta 1420 (strict — il comando fallisce se la porta è occupata) e apre la finestra Tauri puntata su di esso.

Build di produzione:

npm run tauri build
# oppure, equivalentemente, dato che @tauri-apps/cli è installato localmente:
cargo tauri build

Produce un installer nativo in src-tauri/target/release/bundle/ (.msi/portable su Windows, .dmg/.app su macOS, .deb/.rpm su Linux, a seconda della piattaforma su cui si compila).

Come usare l'app:

  1. Scegli un protocollo (NDT7 · M-Lab o LibreSpeed) dal selettore mostrato quando l'app è inattiva o dopo un test completato.
  2. Facoltativamente apri il Server Browser per scegliere manualmente un paese e un server specifico; altrimenti il server più vicino viene selezionato automaticamente.
  3. Avvia il test. La riga di stato riporta la fase corrente (localizzazione → download → upload → completato), mentre il gauge, il grafico e il pannello metriche si aggiornano in tempo reale.
  4. Attendi almeno 30 secondi tra un test e l'altro (imposto dall'app) prima di avviarne uno nuovo.

Protocolli 📡

NDT7 — M-Lab 📶

Scoperta del server:

GET https://locate.measurementlab.net/v2/nearest/ndt/ndt7

Restituisce i server M-Lab geograficamente più vicini ordinati per latenza (oppure i server vicini alle coordinate del centro di un paese scelto, quando selezionato tramite il Server Browser). OpenSpeed usa il primo risultato, con un solo fallback al secondo in caso di errore — nessun ulteriore tentativo.

Download (15s):

  • Connessione via WSS con header Sec-WebSocket-Protocol: net.measurementlab.ndt.v7.
  • Il server invia un flusso continuo di frame binari; OpenSpeed conta ogni byte ricevuto.
  • speed_mbps = total_bytes × 8 / elapsed_secs / 1_000_000, emesso ogni 250ms.
  • Il server invia anche frame di testo JSON (TCPInfo) con dati diagnostici TCP.

Upload (10s):

  • OpenSpeed invia frame binari a partire da 8KB, fino a un massimo di 1MB (raddoppia quando bulk_size <= total_sent / 16, fedele a ndt7-client-go). Il contenuto del buffer è costituito da lettere ASCII casuali, rigenerate ad ogni ridimensionamento.
  • La velocità di upload è calcolata lato server, da TCPInfo.BytesReceived × 8 / TCPInfo.ElapsedTime_µs — autoritativa secondo le specifiche NDT7.

Timeout assoluto: 55s, che racchiude l'intera sequenza locate + download + upload.

LibreSpeed 🌐

La scoperta del server unisce tre fonti, deduplicate per id del server (le voci integrate vincono, preservando i dati geografici curati):

Fonte Copertura Aggiornamento
JSON integrato (global_librespeed_servers.json) 22 server, 17 paesi Incluso nell'app
GARR (speedtest.garr.it/servers.json) Rete italiana della ricerca e dell'istruzione Fetch live
Directory ufficiale (librespeed.org/backend-servers/servers.php) ~45 server pubblici Fetch live, timeout 4s

La selezione automatica del server più vicino usa la distanza euclidea tra la geolocalizzazione dell'utente (da ipinfo.io) e le coordinate lat/lon di ogni server. I paesi senza server pubblici LibreSpeed (AU, BR, CA, FR, SE, NO, PT, ES, …) sono semplicemente assenti dalla lista — NDT7 copre questi casi tramite l'infrastruttura globale di M-Lab.

Ping (prima del test): 10 richieste HTTP HEAD consecutive a <server>/ping.phpmin_rtt_ms + jitter_ms. La risoluzione DNS dell'hostname del server e una GET a <server>/getIP.php (IP del client) vengono eseguite in parallelo al ping tramite tokio::join!.

Download (10s): 3 flussi HTTP GET concorrenti verso <server>/garbage.php?ckSize=10 (10MB ciascuno), in loop per la durata del test; i byte vengono contati dai chunk in streaming, emessi ogni 250ms.

Upload (8s): 3 richieste HTTP POST concorrenti, ciascuna con un blob casuale da 2MB, in loop per la durata del test; i byte vengono contati sulle risposte andate a buon fine, emessi ogni 250ms.

Timeout assoluto: 60s.

Guida alle Metriche 📊

NDT7 📶

Metrica Etichetta UI Fonte Descrizione Buono Discreto Scarso
Ping migliore min_rtt_ms TCPInfo.MinRTT / 1000 RTT minimo registrato dallo stack TCP del server durante il download ≤20ms ≤80ms >80ms
Ping medio rtt_ms TCPInfo.RTT / 1000 RTT smussato più recente dallo stack TCP del server ≤30ms ≤100ms >100ms
Jitter jitter_ms media |RTT[i]-RTT[i-1]| Variazione dell'RTT su tutti i campioni TCPInfo del download, calcolata a fine download ≤5ms ≤20ms >20ms
Perdita di pacchetti retransmission_rate BytesRetrans / BytesSent × 100 Percentuale di byte che il server ha dovuto ritrasmettere; >5% attiva un avviso ambra ≤1% ≤5% >5%
IP server server_ip ConnectionInfo.Server IP:porta del server NDT7
Il tuo IP client_ip ConnectionInfo.Client Il tuo IP pubblico:porta come visto dal server

Tutti i valori TCPInfo sono in microsecondi; OpenSpeed divide per 1000 per mostrarli in millisecondi. Il jitter viene preservato durante la fase di upload tramite un merge lato frontend (il TCPInfo dell'upload emette jitter_ms: null, e il frontend mantiene il valore della fase di download).

LibreSpeed 🌐

Metrica Etichetta UI Fonte Descrizione Buono Discreto Scarso
Ping HTTP min_rtt_ms minimo di 10 round-trip HEAD Round-trip HTTP più veloce verso il server; leggermente più alto del ping TCP puro per via dell'overhead HTTP ≤30ms ≤100ms >100ms
Jitter jitter_ms media |RTT[i]-RTT[i-1]| su 9 coppie di ping consecutive Stabilità della connessione HTTP ≤5ms ≤20ms >20ms
IP server server_ip Lookup DNS dell'hostname del server IP del server di test
Il tuo IP client_ip Risposta JSON getIpURL Il tuo IP pubblico come visto dal server

LibreSpeed non fornisce la perdita di pacchetti (nessun canale di ritorno TCP) né una metrica di ping medio distinta dal ping migliore.

Architettura 🏗️

OpenSpeed/
└── open_speed/
    ├── src/                          ← Frontend React 19
    │   ├── App.tsx                   ← Dashboard, listener IPC, selettore protocollo
    │   ├── index.css                 ← Tailwind v4 (@import "tailwindcss")
    │   ├── types/ipc.ts              ← Interfacce TypeScript per tutti i payload IPC
    │   └── components/
    │       ├── SpeedGauge.tsx        ← Gauge analogico SVG, scala automatica 25-2500 Mbps
    │       ├── SpeedChart.tsx        ← Grafico a linee Recharts (DL=blu, UL=verde)
    │       ├── MetricsPanel.tsx      ← Card metriche sensibili alla qualità, set per protocollo
    │       ├── NetworkBadge.tsx      ← Badge Ethernet/WiFi + nome ISP + bandiera paese
    │       └── ServerBrowser.tsx     ← Modale di selezione server (filtro paese, ping, selezione)
    └── src-tauri/src/
        ├── lib.rs                    ← Comandi Tauri, AppState, controlli di sicurezza
        ├── models.rs                 ← Struct condivise (payload IPC + JSON NDT7)
        ├── hardware.rs               ← Rilevamento interfaccia di rete via sysinfo
        ├── assets/
        │   ├── country_coords.json              ← 57 paesi con lat/lon (browser NDT7)
        │   └── global_librespeed_servers.json    ← 22 server LibreSpeed integrati
        └── network/
            ├── locate.rs             ← Locate API M-Lab → server NDT7 più vicini
            ├── download.rs           ← Download NDT7 (15s, conteggio frame binari)
            ├── upload.rs             ← Upload NDT7 (10s, scalatura 8KB→1MB)
            └── librespeed/
                ├── servers.rs        ← GARR + fetch live librespeed.org + lista integrata
                ├── ping.rs           ← 10× HTTP HEAD → min_ms + jitter_ms
                ├── download.rs       ← 3 GET concorrenti, 10s, emissione ogni 250ms
                └── upload.rs         ← 3 POST concorrenti, 8s, emissione ogni 250ms

Eventi IPC (Rust → Frontend):

Evento Payload Quando viene emesso
test-status { status, message, server, server_city, server_country, server_country_code } Ad ogni transizione di fase
download-speed { speed_mbps, elapsed_ms } Ogni 250ms durante il download
upload-speed { speed_mbps, elapsed_ms } Ogni 250ms durante l'upload
test-metrics { min_rtt_ms, rtt_ms, retransmission_rate, jitter_ms, server_ip, client_ip } Ad ogni frame TCPInfo (NDT7) o una volta dopo il ping (LibreSpeed)

Comandi Tauri (Frontend → Rust):

Comando Ritorna Note
start_speed_test(server?) Promise<void> NDT7; override manuale opzionale del server; genera un errore in caso di rate-limit o test concorrente
start_librespeed_test(server?, userLat?, userLon?) Promise<void> LibreSpeed; stessi controlli; le coordinate abilitano la selezione automatica del server più vicino
get_network_info() Promise<NetworkInfoPayload> Tipo e nome dell'interfaccia
get_isp_info() Promise<IspInfoPayload> Chiama ipinfo.io/json una volta all'avvio — ISP, paese, lat/lon
get_server_list(protocol, countryCode?, userLat?, userLon?) Promise<ServerListItem[]> Alimenta il Server Browser

Controlli di Sicurezza 🛡️

Controllo Valore Dettagli
Rate limit 30s tra un test e l'altro Condiviso tra i due protocolli; il timer parte dopo la fine del test, non all'inizio
Blocco test concorrenti Mutex<bool> Rifiuta una seconda invoke() mentre un test è in corso
Timeout assoluto NDT7 55s Racchiude l'intera sequenza locate + download + upload
Timeout assoluto LibreSpeed 60s Racchiude l'intera sequenza locate + ping + download + upload
Timeout download/upload NDT7 15s / 10s Stop forzato in download.rs / upload.rs
Timeout download/upload LibreSpeed 10s / 8s Stop forzato in librespeed/download.rs / librespeed/upload.rs
Timeout handshake WebSocket 7s Applicato alla connessione WS
Fallback server NDT7 Massimo 1 Ricade solo sul secondo risultato della Locate API; nessun ciclo di retry
Chiamata Locate API Una volta per test Una singola chiamata a get_nearest_servers() per ogni run_full_test

Questi controlli sono considerati non negoziabili in questo progetto e non devono essere rimossi o indeboliti.

Licenza e Attribuzioni 📄

OpenSpeed è rilasciato sotto GNU Affero General Public License v3.0 — vedi LICENSE.

  • NDT7: l'implementazione del protocollo è una reimplementazione Rust indipendente, che usa ndt7-client-go (Apache License 2.0, © Measurement Lab) esclusivamente come riferimento di protocollo — nessun codice è stato copiato. L'attribuzione volontaria è riportata in NOTICE e nei commenti in testa a network/locate.rs, network/download.rs e network/upload.rs.
  • LibreSpeed: il client è un'implementazione originale, non derivata da librespeed/speedtest-cli (LGPL v3) — nessun codice è stato copiato, sono state referenziate solo le semantiche del protocollo di rete. Vedi NOTICE per i dettagli.
  • Le misurazioni di rete si appoggiano all'infrastruttura pubblica NDT7 di M-Lab e a GARR / alla directory ufficiale dei server pubblici LibreSpeed; nessuna delle due viene inclusa o ridistribuita da questo progetto.

Limiti Noti ⚠️

  • link_speed_mbps è sempre nullsysinfo non espone la velocità del link (richiederebbe il crate netdev).
  • Nessuno storico dei risultati — le misurazioni non vengono salvate tra una sessione e l'altra.
  • LibreSpeed: i paesi senza server pubblici (AU, BR, CA, FR, SE, NO, PT, ES, …) mostrano una lista vuota nel Server Browser — usa NDT7 in questi casi.

About

OpenSpeed is a native desktop internet speed test app. It measures download/upload speed, ping, jitter, and packet loss via two protocols — NDT7 (M-Lab) and LibreSpeed — with a global server browser, real-time gauges, and safety-first rate limiting.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages