Stream reader
This commit is contained in:
parent
76be5e37d5
commit
1d4efd738c
1 changed files with 24 additions and 5 deletions
|
@ -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 });
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue