Stream reader

This commit is contained in:
Manav Rathi 2024-04-23 12:03:55 +05:30
parent 76be5e37d5
commit 1d4efd738c
No known key found for this signature in database

View file

@ -1,15 +1,16 @@
/**
* @file stream data to-from renderer using a custom protocol handler.
*/
import { protocol } from "electron/main";
import { net, protocol } from "electron/main";
import { createWriteStream, existsSync } from "node:fs";
import fs from "node:fs/promises";
import { Readable } from "node:stream";
import { pathToFileURL } from "node:url";
import log from "./log";
/**
* Register a protocol handler that we use for streaming large files between the
* main process (node) and the renderer process (browser) layer.
* main (Node.js) and renderer (Chromium) processes.
*
* [Note: IPC streams]
*
@ -17,11 +18,14 @@ import log from "./log";
* across IPC. And passing the entire contents of the file is not feasible for
* large video files because of the memory pressure the copying would entail.
*
* As an alternative, we register a custom protocol handler that can provided a
* As an alternative, we register a custom protocol handler that can provides a
* bi-directional stream. The renderer can stream data to the node side by
* streaming the request. The node side can stream to the renderer side by
* streaming the response.
*
* The stream is not full duplex - while both reads and writes can be streamed,
* they need to be streamed separately.
*
* See also: [Note: Transferring large amount of data over IPC]
*
* Depends on {@link registerPrivilegedSchemes}.
@ -29,12 +33,16 @@ import log from "./log";
export const registerStreamProtocol = () => {
protocol.handle("stream", async (request: Request) => {
const url = request.url;
// The request URL contains the command to run as the host, and the
// pathname of the file as the path. For example,
//
// stream://write/path/to/file
// host-pathname-----
//
const { host, pathname } = new URL(url);
// Convert e.g. "%20" to spaces.
const path = decodeURIComponent(pathname);
switch (host) {
/* stream://write/path/to/file */
/* host-pathname----- */
case "write":
try {
await writeStream(path, request.body);
@ -46,6 +54,17 @@ export const registerStreamProtocol = () => {
{ status: 500 },
);
}
case "read":
try {
return net.fetch(pathToFileURL(path).toString());
} catch (e) {
log.error(`Failed to read stream for ${url}`, e);
return new Response(`Failed to read stream: ${e.message}`, {
status: 500,
});
}
default:
return new Response("", { status: 404 });
}