






















@@ -2554,6 +2554,7 @@ async function configureDiscordSmoke(params) {
25542554export async function readBoundedCrossOsResponseText(
25552555response: Response,
25562556maxChars = CROSS_OS_FETCH_BODY_MAX_CHARS,
2557+options: { signal?: AbortSignal | null } = {},
25572558): Promise<string> {
25582559if (!response.body) {
25592560return "";
@@ -2563,10 +2564,11 @@ export async function readBoundedCrossOsResponseText(
25632564const decoder = new TextDecoder();
25642565let text = "";
25652566let truncated = false;
2567+let aborted = false;
2566256825672569try {
25682570while (text.length <= maxChars) {
2569-const { done, value } = await reader.read();
2571+const { done, value } = await readCrossOsResponseChunk(reader, options.signal);
25702572if (done) {
25712573text += decoder.decode();
25722574break;
@@ -2579,8 +2581,11 @@ export async function readBoundedCrossOsResponseText(
25792581break;
25802582}
25812583}
2584+} catch (error) {
2585+aborted = options.signal?.aborted === true;
2586+throw error;
25822587} finally {
2583-if (truncated) {
2588+if (truncated || aborted) {
25842589await reader.cancel().catch(() => undefined);
25852590} else {
25862591reader.releaseLock();
@@ -2590,6 +2595,36 @@ export async function readBoundedCrossOsResponseText(
25902595return truncated ? `${text}\n[truncated]` : text;
25912596}
259225972598+function readCrossOsResponseChunk(
2599+reader: ReadableStreamDefaultReader<Uint8Array>,
2600+signal?: AbortSignal | null,
2601+): Promise<ReadableStreamReadResult<Uint8Array>> {
2602+if (!signal) {
2603+return reader.read();
2604+}
2605+if (signal.aborted) {
2606+throw crossOsAbortReason(signal);
2607+}
2608+return new Promise((resolveRead, rejectRead) => {
2609+const onAbort = () => rejectRead(crossOsAbortReason(signal));
2610+signal.addEventListener("abort", onAbort, { once: true });
2611+reader
2612+.read()
2613+.then(resolveRead, rejectRead)
2614+.finally(() => {
2615+signal.removeEventListener("abort", onAbort);
2616+});
2617+});
2618+}
2619+2620+function crossOsAbortReason(signal: AbortSignal): Error {
2621+const reason = signal.reason;
2622+if (reason instanceof Error) {
2623+return reason;
2624+}
2625+return new Error(typeof reason === "string" ? reason : "The operation was aborted.");
2626+}
2627+25932628export function dashboardHtmlMarkerStatus(html: string): {
25942629 app: boolean;
25952630 ready: boolean;
@@ -2647,11 +2682,12 @@ async function waitForDiscordMessage(params) {
26472682let response;
26482683let text;
26492684try {
2685+const init = buildDiscordFetchInit(params.token);
26502686response = await fetch(
26512687`https://discord.com/api/v10/channels/${params.channelId}/messages?limit=20`,
2652-buildDiscordFetchInit(params.token),
2688+init,
26532689);
2654-text = await readBoundedCrossOsResponseText(response);
2690+text = await readBoundedCrossOsResponseText(response, undefined, { signal: init.signal });
26552691} catch {
26562692await sleep(2_000);
26572693continue;
@@ -2680,20 +2716,21 @@ export function buildDiscordFetchInit(token, init = {}) {
26802716}
2681271726822718async function postDiscordMessage(params) {
2719+const init = buildDiscordFetchInit(params.token, {
2720+method: "POST",
2721+headers: {
2722+"Content-Type": "application/json",
2723+},
2724+body: JSON.stringify({
2725+content: params.content,
2726+flags: 4096,
2727+}),
2728+});
26832729const response = await fetch(
26842730`https://discord.com/api/v10/channels/${params.channelId}/messages`,
2685-buildDiscordFetchInit(params.token, {
2686-method: "POST",
2687-headers: {
2688-"Content-Type": "application/json",
2689-},
2690-body: JSON.stringify({
2691-content: params.content,
2692-flags: 4096,
2693-}),
2694-}),
2731+init,
26952732);
2696-const text = await readBoundedCrossOsResponseText(response);
2733+const text = await readBoundedCrossOsResponseText(response, undefined, { signal: init.signal });
26972734if (!response.ok) {
26982735throw new Error(`Failed to post Discord smoke message: ${text}`);
26992736}
@@ -3525,10 +3562,11 @@ async function runDashboardSmoke(params) {
35253562attempt += 1;
35263563logStream.write(`${new Date().toISOString()} attempt=${attempt} url=${dashboardUrl}\n`);
35273564try {
3565+const signal = AbortSignal.timeout(CROSS_OS_DASHBOARD_FETCH_TIMEOUT_MS);
35283566const response = await fetch(dashboardUrl, {
3529-signal: AbortSignal.timeout(CROSS_OS_DASHBOARD_FETCH_TIMEOUT_MS),
3567+ signal,
35303568});
3531-const html = await readBoundedCrossOsResponseText(response);
3569+const html = await readBoundedCrossOsResponseText(response, undefined, { signal });
35323570const markers = dashboardHtmlMarkerStatus(html);
35333571const assetUrls = resolveDashboardAssetUrls(dashboardUrl, html);
35343572if (response.ok && markers.ready) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。