MotorSignal-App/website/app/api/ops/infrastructure/speedtest/route.ts

187 lines
5.5 KiB
TypeScript

import { cookies } from 'next/headers';
import { NextRequest, NextResponse } from 'next/server';
import { hasValidOrigin } from '../../../../../lib/request-origin';
function getClientIp(request: NextRequest): string {
const forwarded = request.headers.get('x-forwarded-for');
if (forwarded) {
const firstIp = forwarded.split(',')[0].trim();
if (firstIp) return firstIp;
}
return request.headers.get('x-real-ip') ?? '127.0.0.1';
}
async function getOpsToken(): Promise<string | undefined> {
const cookieStore = await cookies();
const isProduction = process.env.NODE_ENV === 'production' && process.env.NEXT_PUBLIC_APP_ENV === 'production';
return isProduction
? cookieStore.get('__Host-motorsignal_ops')?.value
: cookieStore.get('__Host-motorsignal_ops')?.value ??
cookieStore.get('motorsignal_ops')?.value;
}
export async function GET(request: NextRequest) {
const opsToken = await getOpsToken();
if (!opsToken) {
return NextResponse.json(
{ detail: 'Authentication required.' },
{ status: 401 }
);
}
const { searchParams } = new URL(request.url);
const action = searchParams.get('action') || 'ping';
const clientIp = getClientIp(request);
if (action === 'ping') {
return NextResponse.json(
{
status: 'ok',
client_ip: clientIp,
server_target: 'MotorSignal Host Edge',
timestamp: Date.now(),
},
{
headers: {
'Cache-Control': 'no-store, no-cache, must-revalidate',
'X-Client-IP': clientIp,
},
}
);
}
if (action === 'download') {
const rawBytes = parseInt(searchParams.get('bytes') || '2500000', 10);
const byteCount = Math.min(Math.max(100000, isNaN(rawBytes) ? 2500000 : rawBytes), 10000000);
const chunk = new Uint8Array(byteCount);
// Fill pseudo-random patterns to prevent transparent gzip collapse
for (let i = 0; i < byteCount; i += 4096) {
chunk[i] = (i * 31) & 0xff;
}
return new Response(chunk, {
status: 200,
headers: {
'Content-Type': 'application/octet-stream',
'Content-Length': byteCount.toString(),
'Cache-Control': 'no-store, no-cache, no-transform',
'X-Client-IP': clientIp,
},
});
}
return NextResponse.json({
status: 'available',
modes: ['client_to_server', 'server_to_external'],
client_ip: clientIp,
});
}
export async function POST(request: NextRequest) {
if (!hasValidOrigin(request)) {
return NextResponse.json({ detail: 'Invalid request origin.' }, { status: 403 });
}
const opsToken = await getOpsToken();
if (!opsToken) {
return NextResponse.json(
{ detail: 'Authentication required.' },
{ status: 401 }
);
}
const clientIp = getClientIp(request);
const action = request.nextUrl.searchParams.get('action');
// 1. Client to server upload benchmark handler
if (action === 'upload') {
const t0 = Date.now();
const arrayBuffer = await request.arrayBuffer();
const durationMs = Math.max(1, Date.now() - t0);
return NextResponse.json({
status: 'completed',
received_bytes: arrayBuffer.byteLength,
server_duration_ms: durationMs,
client_ip: clientIp,
tested_at: new Date().toISOString(),
});
}
// 2. Client to server speedtest audit recorder (forward to backend ops_audit)
if (action === 'record_client_result') {
const body = await request.json().catch(() => null);
const baseUrl = process.env.MOTORSIGNAL_API_BASE_URL ?? 'https://api.motorsignal.app';
try {
const response = await fetch(`${baseUrl}/api/v1/ops/infrastructure/speedtest`, {
method: 'POST',
headers: {
authorization: `Bearer ${opsToken}`,
'content-type': 'application/json',
accept: 'application/json',
},
body: JSON.stringify({
mode: 'client_to_server',
latency_ms: body?.latency_ms,
download_mbps: body?.download_mbps,
upload_mbps: body?.upload_mbps,
client_ip: clientIp,
}),
cache: 'no-store',
});
if (response.ok) {
const data = await response.json();
return NextResponse.json(data);
}
} catch {
// Non-fatal if backend audit log proxy fails
}
return NextResponse.json({
status: 'completed',
mode: 'client_to_server',
client_ip: clientIp,
recorded: true,
});
}
// 3. Server to external upstream benchmark handler (default)
const baseUrl = process.env.MOTORSIGNAL_API_BASE_URL ?? 'https://api.motorsignal.app';
try {
const response = await fetch(`${baseUrl}/api/v1/ops/infrastructure/speedtest`, {
method: 'POST',
headers: {
authorization: `Bearer ${opsToken}`,
accept: 'application/json',
},
cache: 'no-store',
});
if (response.status === 401) {
return NextResponse.json(
{ detail: 'Your Operations session has expired.' },
{ status: 401 }
);
}
if (response.status === 403) {
return NextResponse.json(
{ detail: 'You do not have authority to run network speedtests.' },
{ status: 403 }
);
}
if (!response.ok) {
return NextResponse.json(
{ detail: 'Operations speedtest service temporarily unavailable.' },
{ status: response.status >= 500 ? response.status : 503 }
);
}
const data = await response.json();
return NextResponse.json(data);
} catch {
return NextResponse.json(
{ detail: 'Unable to connect to Operations platform.' },
{ status: 503 }
);
}
}