empz
empz

Reputation: 11808

How to stream and consume 2 binary files with Hono and Bun?

I need to stream 2 binary files from the filesystem from a Hono app to another Hono app.

Doing just one file is very easy with Bun and Hono Streaming API.

// Streaming app
import { Hono } from "hono";
import { stream } from "hono/streaming";

const app = new Hono();

app.get("/", (c) => {
    return stream(c, async (stream) => {
        // Write a process to be executed when aborted.
        stream.onAbort(() => {
            console.log("Aborted!");
        });

        // Pipe the video stream.
        const videoFile = Bun.file("./data/worker/video.mp4");
        console.log("Streaming video file...");
        await stream.pipe(videoFile.stream());

        // Pipe the audio stream
        // const audioFile = Bun.file("./data/worker/audio.mp4");
        // console.log("Streaming audio file...");
        // await stream.pipe(audioFile.stream());

        console.log("Done!");
    });
});

console.log("Worker is running on port 3001");

export default {
    port: 3001,
    fetch: app.fetch,
};

And consuming it from another app

app.get("/", async (c) => {
    console.log("Streaming files from worker...");

    const response = await fetch("http://localhost:3001/");

    if (!response.ok) {
        return c.json({ error: "Failed to stream files from worker" }, 500);
    }

    await Bun.write("./data/output/video.mp4", response.body);

    return c.json({ message: "File streamed successfully" });
});

Now, how do I add a second file to the stream? The consumer will need to read both files and write them to the filesystem.

Upvotes: 0

Views: 543

Answers (1)

Szauka
Szauka

Reputation: 1

Streaming App

import { Hono } from "hono";
import { stream } from "hono/streaming";

const app = new Hono();

app.get("/", (c) => {
    return stream(c, async (stream) => {
        stream.onAbort(() => {
            console.log("Aborted!");
        });

        // Pipe the first video file
        const videoFile = Bun.file("./data/worker/video.mp4");
        console.log("Streaming video file...");
        await stream.pipe(videoFile.stream());

        // Send a delimiter or an identifier to signal the end of the first file
        await stream.write(new TextEncoder().encode("\n--file-boundary--\n"));

        // Pipe the second audio file
        const audioFile = Bun.file("./data/worker/audio.mp4");
        console.log("Streaming audio file...");
        await stream.pipe(audioFile.stream());

        console.log("Done streaming both files!");
    });
});

console.log("Worker is running on port 3001");

export default {
    port: 3001,
    fetch: app.fetch,
};

The other app

import { Hono } from "hono";
import { Bun } from "bun"; // Import Bun for filesystem handling if needed.

const app = new Hono();

app.get("/", async (c) => {
    console.log("Streaming files from worker...");

    const response = await fetch("http://localhost:3001/");
    if (!response.ok) {
        return c.json({ error: "Failed to stream files from worker" }, 500);
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = "";
    let isVideo = true; // Start with the assumption that the first file is the video

    while (true) {
        const { done, value } = await reader.read();
        if (done) break;

        // Append the chunk to the buffer
        buffer += decoder.decode(value, { stream: true });

        // Check for file boundary
        if (buffer.includes("--file-boundary--")) {
            const [firstFilePart, secondFilePart] = buffer.split("--file-boundary--");

            // Write the first file part to disk
            const firstFile = new TextEncoder().encode(firstFilePart.trim());
            await Bun.write(isVideo ? "./data/output/video.mp4" : "./data/output/audio.mp4", firstFile);

            // Set up for the next file
            buffer = secondFilePart;
            isVideo = !isVideo;
        }
    }

    // Write any remaining part to the second file
    if (buffer) {
        const finalFile = new TextEncoder().encode(buffer.trim());
        await Bun.write(isVideo ? "./data/output/video.mp4" : "./data/output/audio.mp4", finalFile);
    }

    return c.json({ message: "Both files streamed successfully" });
});

export default app;

Upvotes: -1

Related Questions