rosdiff / api /static /foxglove-embed /ParentFetchBridge.js
Chandra Kiran
Harden simulation runs: official Foxglove embed, WebM video, CI image build
04ad412 unverified
Raw History Blame Contribute Delete
2.19 kB
import { toError } from "./toError.js";
/** Owns the parent half of the iframe fetch transport. */
export class ParentFetchBridge {
port;
#parentPort;
#fetch;
#requests = new Map();
#closed = false;
constructor(fetchFn) {
this.#fetch = fetchFn;
const channel = new MessageChannel();
this.port = channel.port2;
channel.port1.onmessage = this.#handleMessage;
channel.port1.start();
this.#parentPort = channel.port1;
}
close() {
if (this.#closed) {
return;
}
this.#closed = true;
for (const [port, controller] of this.#requests) {
controller.abort();
port.close();
}
this.#requests.clear();
this.#parentPort.close();
}
#handleMessage = (event) => {
if (this.#closed) {
return;
}
void this.#fetchStream(event.data.url, event.data.options, event.data.port);
};
async #fetchStream(url, options, port) {
const controller = new AbortController();
this.#requests.set(port, controller);
port.onmessage = (event) => {
if (event.data.type === "abort") {
controller.abort();
}
this.#finishRequest(port);
};
port.start();
try {
const response = await this.#fetch(url, {
...options,
signal: controller.signal,
});
const message = {
type: "response",
status: response.status,
statusText: response.statusText,
headers: [...response.headers.entries()],
body: response.body,
};
port.postMessage(message, response.body ? [response.body] : []);
}
catch (err) {
const error = toError(err);
port.postMessage({
type: "error",
name: error.name,
message: error.message,
});
this.#finishRequest(port);
}
}
#finishRequest(port) {
this.#requests.delete(port);
port.close();
}
}