proxy speedtest update

This commit is contained in:
2026-07-03 14:20:07 +07:00
parent 052a4081b3
commit 7175a2b450
4 changed files with 298 additions and 87 deletions
+29 -6
View File
@@ -19,18 +19,24 @@ struct CommentPayload {
message: String,
}
// Восстановленный генератор нагрузки для спидтеста (25 MB)
// Генератор нагрузки для спидтеста (64 MB на один запрос).
//
// Байты генерируются линейным конгруэнтным генератором (LCG), а не просто
// заполняются нулями: нулевой (или вообще любой сильно сжимаемый) блоб при
// передаче через gzip/brotli в HTTP-стеке "похудеет" в десятки раз, и клиент
// измерит скорость сжатия, а не скорость сети. LCG даёт дешёвый (без крипто-
// рандома и внешних зависимостей) псевдослучайный поток байт, который не
// сжимается, поэтому размер тела на проводе честно равен 25 МБ. Генерируется
// один раз при первом обращении (LazyLock) и переиспользуется для всех
// последующих запросов.
// сжимается, поэтому размер тела на проводе честно равен заявленному объёму.
// Генерируется один раз при первом обращении (LazyLock) и переиспользуется
// для всех последующих запросов (клонирование Bytes — это инкремент
// refcount, а не копия буфера, так что параллельные запросы дёшевы).
//
// 64 MB, а не 25 — клиент теперь качает окно фиксированной ДЛИТЕЛЬНОСТИ
// несколькими параллельными потоками и переоткрывает поток, как только он
// исчерпал блоб. Больший блоб просто снижает частоту переоткрытий на очень
// быстрых каналах, не меняя семантику теста.
static RANDOM_PAYLOAD: LazyLock<Bytes> = LazyLock::new(|| {
let mut data = vec![0u8; 25 * 1024 * 1024];
let mut data = vec![0u8; 64 * 1024 * 1024];
let mut state: u32 = 123456789;
for byte in data.iter_mut() {
state = state.wrapping_mul(1103515245).wrapping_add(12345);
@@ -60,7 +66,7 @@ async fn main() {
let app = Router::new()
.route("/api/comments", post(create_comment))
.route("/api/speedtest/ping", get(|| async { "pong" }))
.route("/api/speedtest/ping", get(speedtest_ping))
.route("/api/speedtest/download", get(speedtest_download))
.route("/api/speedtest/upload", post(speedtest_upload))
.layer(DefaultBodyLimit::max(100 * 1024 * 1024))
@@ -178,6 +184,23 @@ async fn create_comment(
}
}
// Без no-store браузер/промежуточный кэш мог бы отдать закэшированный "pong"
// вместо реального round-trip'а — и клиентский спидтест мерил бы кэш, а не сеть.
async fn speedtest_ping() -> impl IntoResponse {
(
[
(
header::CACHE_CONTROL,
header::HeaderValue::from_static(
"no-store, no-cache, must-revalidate, max-age=0",
),
),
(header::PRAGMA, header::HeaderValue::from_static("no-cache")),
],
"pong",
)
}
async fn speedtest_download() -> impl IntoResponse {
println!("📊 [SPEEDTEST] Download requested");
let body = RANDOM_PAYLOAD.clone();