Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
177 lines
5.1 KiB
TypeScript
177 lines
5.1 KiB
TypeScript
/**
|
|
* Stub agent for discover→spread E2E — acknowledges discover_and_join and reports join_lane.
|
|
*/
|
|
import type { APIRequestContext } from '@playwright/test';
|
|
import { fetchFleetSecret, waitForServerHealth } from './fixtures';
|
|
|
|
export const E2E_DISCOVER_AGENT_ID = 'e2e-discover-spread-agent';
|
|
export const E2E_DISCOVER_AGENT_HOSTNAME = 'E2E-Discover-Host';
|
|
export const E2E_DISCOVER_JOIN_LANE = 'dns_txt';
|
|
export const E2E_DISCOVER_JOIN_LABEL = 'DNS TXT';
|
|
|
|
const baseURL = process.env.AETHERFORGE_URL || 'http://127.0.0.1:8989';
|
|
const STATS_INTERVAL_MS = 1_000;
|
|
|
|
type HubMessage = {
|
|
type: string;
|
|
payload: string | Record<string, unknown>;
|
|
};
|
|
|
|
function parsePayload(payload: HubMessage['payload']): Record<string, unknown> {
|
|
if (typeof payload === 'string') {
|
|
return JSON.parse(payload) as Record<string, unknown>;
|
|
}
|
|
return payload;
|
|
}
|
|
|
|
function wsAgentUrl(baseUrl: string): string {
|
|
const trimmed = baseUrl.replace(/\/$/, '');
|
|
return trimmed.replace(/^http/i, 'ws') + '/ws/agent';
|
|
}
|
|
|
|
function send(ws: WebSocket, type: string, payload: Record<string, unknown>): void {
|
|
ws.send(JSON.stringify({ type, payload }));
|
|
}
|
|
|
|
function sendStubStats(ws: WebSocket, joinLane?: string): void {
|
|
send(ws, 'stats', {
|
|
hashrate_15s: 42,
|
|
hashrate_1m: 42,
|
|
hashrate_15m: 42,
|
|
shares_submitted: 0,
|
|
shares_accepted: 0,
|
|
cpu_usage_pct: 5,
|
|
memory_usage_pct: 40,
|
|
uptime_seconds: 120,
|
|
active_method: 'inprocess',
|
|
mining_hashrate: 42,
|
|
lotl_tier: 'inprocess',
|
|
lotl_attempts: [
|
|
{ tier: 'vuln_recon', ok: true, duration_ms: 200, phase: 'recon' },
|
|
{ tier: 'dns_txt', ok: true, duration_ms: 450, phase: 'deploy' },
|
|
],
|
|
...(joinLane ? { join_lane: joinLane } : {}),
|
|
});
|
|
}
|
|
|
|
async function connectDiscoverSpreadStub(baseUrl: string, fleetSecret: string): Promise<() => void> {
|
|
const ws = new WebSocket(wsAgentUrl(baseUrl));
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
const timer = setTimeout(() => reject(new Error('discover stub ws open timeout')), 10_000);
|
|
ws.addEventListener(
|
|
'open',
|
|
() => {
|
|
clearTimeout(timer);
|
|
resolve();
|
|
},
|
|
{ once: true },
|
|
);
|
|
ws.addEventListener(
|
|
'error',
|
|
() => {
|
|
clearTimeout(timer);
|
|
reject(new Error('discover stub ws connection failed'));
|
|
},
|
|
{ once: true },
|
|
);
|
|
});
|
|
|
|
send(ws, 'auth', {
|
|
agent_id: E2E_DISCOVER_AGENT_ID,
|
|
fleet_secret: fleetSecret,
|
|
hostname: E2E_DISCOVER_AGENT_HOSTNAME,
|
|
version: '1.0.0-e2e',
|
|
platform: 'windows',
|
|
arch: 'amd64',
|
|
cpu_cores: 4,
|
|
memory_gb: 8,
|
|
});
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
const timer = setTimeout(() => reject(new Error('discover stub auth timeout')), 30_000);
|
|
const onMessage = (ev: MessageEvent) => {
|
|
let msg: HubMessage;
|
|
try {
|
|
msg = JSON.parse(String(ev.data)) as HubMessage;
|
|
} catch {
|
|
return;
|
|
}
|
|
if (msg.type !== 'auth_response') return;
|
|
clearTimeout(timer);
|
|
ws.removeEventListener('message', onMessage);
|
|
const body = parsePayload(msg.payload);
|
|
if (body.success !== true) {
|
|
reject(new Error(`discover stub auth rejected: ${JSON.stringify(body)}`));
|
|
return;
|
|
}
|
|
resolve();
|
|
};
|
|
ws.addEventListener('message', onMessage);
|
|
});
|
|
|
|
sendStubStats(ws);
|
|
const statsTimer = setInterval(() => sendStubStats(ws), STATS_INTERVAL_MS);
|
|
|
|
ws.addEventListener('message', (ev) => {
|
|
let msg: HubMessage;
|
|
try {
|
|
msg = JSON.parse(String(ev.data)) as HubMessage;
|
|
} catch {
|
|
return;
|
|
}
|
|
if (msg.type !== 'command') return;
|
|
const payload = parsePayload(msg.payload);
|
|
const action = String(payload.action ?? '');
|
|
const command = String(payload.command ?? '').trim().toLowerCase();
|
|
|
|
if (action === 'discover_and_join' || command === 'discover_and_join') {
|
|
send(ws, 'command_result', {
|
|
action: 'discover_and_join',
|
|
success: true,
|
|
message: `discover_and_join ok — join_lane=${E2E_DISCOVER_JOIN_LANE}`,
|
|
});
|
|
sendStubStats(ws, E2E_DISCOVER_JOIN_LANE);
|
|
return;
|
|
}
|
|
|
|
send(ws, 'command_result', { action, success: true, message: 'e2e-discover-stub-ok' });
|
|
});
|
|
|
|
return () => {
|
|
clearInterval(statsTimer);
|
|
ws.close();
|
|
};
|
|
}
|
|
|
|
let serverReady = false;
|
|
let disconnectStub: (() => void) | null = null;
|
|
let connectPromise: Promise<boolean> | null = null;
|
|
|
|
export async function ensureDiscoverSpreadStub(request: APIRequestContext): Promise<boolean> {
|
|
if (disconnectStub) return serverReady;
|
|
if (!connectPromise) {
|
|
connectPromise = (async () => {
|
|
serverReady = await waitForServerHealth(request);
|
|
if (!serverReady) return false;
|
|
|
|
const fleetSecret = await fetchFleetSecret(request);
|
|
disconnectStub = await connectDiscoverSpreadStub(baseURL, fleetSecret);
|
|
await new Promise((r) => setTimeout(r, 2_500));
|
|
return true;
|
|
})();
|
|
}
|
|
return connectPromise;
|
|
}
|
|
|
|
export function isDiscoverSpreadStubReady(): boolean {
|
|
return serverReady;
|
|
}
|
|
|
|
export function teardownDiscoverSpreadStub(): void {
|
|
disconnectStub?.();
|
|
disconnectStub = null;
|
|
connectPromise = null;
|
|
serverReady = false;
|
|
}
|