HWLAB_PROXY_PROBE_PHASE=__HWLAB_PROXY_PHASE_SHELL__ HWLAB_PROXY_PROBE_URL=__HWLAB_PROXY_TARGET_SHELL__ node <<'NODE' || echo '{"event":"dependency-proxy-probe-nonblocking","phase":"__HWLAB_PROXY_PHASE__","ok":false,"reason":"probe-failed-but-continuing"}'
const net = require("node:net");

const phase = process.env.HWLAB_PROXY_PROBE_PHASE || "unknown";
const target = new URL(process.env.HWLAB_PROXY_PROBE_URL || "http://deb.debian.org/debian/dists/bookworm/InRelease");
const proxyRaw = process.env.HTTP_PROXY || process.env.http_proxy || "";

function redactProxy(value) {
  if (!value) return "";
  try {
    const parsed = new URL(value);
    if (parsed.username || parsed.password) {
      parsed.username = "***";
      parsed.password = "";
    }
    return parsed.toString();
  } catch {
    return "<invalid-proxy-url>";
  }
}

function emit(payload, exitCode = 0) {
  console.log(JSON.stringify({
    event: "dependency-proxy-probe",
    phase,
    target: target.href,
    proxy: redactProxy(proxyRaw),
    ...payload
  }));
  if (exitCode) process.exit(exitCode);
}

if (!proxyRaw) emit({ ok: false, reason: "proxy-env-missing" }, 21);

let proxy;
try {
  proxy = new URL(proxyRaw);
} catch (error) {
  emit({ ok: false, reason: "proxy-url-invalid", error: error.message }, 22);
}

if (proxy.protocol !== "http:" && proxy.protocol !== "https:") {
  emit({ ok: false, reason: "http-proxy-required", protocol: proxy.protocol }, 23);
}

const startedAt = Date.now();
const socket = net.createConnection({ host: proxy.hostname, port: Number(proxy.port || (proxy.protocol === "https:" ? 443 : 80)) });
let bytes = 0;
let firstByteMs = null;
let responseHead = "";
let finished = false;

const timeout = setTimeout(() => {
  if (finished) return;
  finished = true;
  socket.destroy();
  emit({ ok: false, reason: "timeout", timeoutMs: 15000 }, 24);
}, 15000);

socket.on("connect", () => {
  socket.write("GET " + target.href + " HTTP/1.1\r\nHost: " + target.host + "\r\nUser-Agent: hwlab-node-proxy-probe\r\nConnection: close\r\n\r\n");
});

socket.on("data", (chunk) => {
  if (firstByteMs === null) firstByteMs = Date.now() - startedAt;
  bytes += chunk.length;
  if (responseHead.length < 240) responseHead += chunk.toString("utf8", 0, Math.min(chunk.length, 240 - responseHead.length));
});

socket.on("end", () => {
  if (finished) return;
  finished = true;
  clearTimeout(timeout);
  const totalMs = Date.now() - startedAt;
  const statusLine = responseHead.split("\r\n", 1)[0] || "";
  const statusCode = Number(statusLine.split(" ")[1] || 0);
  const ok = statusLine.startsWith("HTTP/") && statusCode >= 200 && statusCode < 400;
  emit({
    ok,
    reason: ok ? null : "bad-http-status",
    statusLine,
    statusCode,
    firstByteMs,
    totalMs,
    bytes,
    speedBytesPerSecond: totalMs > 0 ? Math.round(bytes * 1000 / totalMs) : 0
  }, ok ? 0 : 25);
});

socket.on("error", (error) => {
  if (finished) return;
  finished = true;
  clearTimeout(timeout);
  emit({ ok: false, reason: "proxy-connect-failed", error: error.message, totalMs: Date.now() - startedAt }, 26);
});
NODE