How to respond with a stream in a Sveltekit server load function
Asked Answered
D

2

6

Below I try to respond with a stream when I receive ticker updates.

+page.server.js:

import YahooFinanceTicker from "yahoo-finance-ticker";

const ticker = new YahooFinanceTicker();
const tickerListener = await ticker.subscribe(["BTC-USD"])

const stream = new ReadableStream({
  start(controller) {
    tickerListener.on("ticker", (ticker) => {
      console.log(ticker.price);
      controller.enqueue(ticker.price);
    });
  }
}); 

export async function load() {

    return response????
};

Note: The YahooFinanceTicker can't run in the browser.

How to handle / set the response in the Sveltekit load function.

Dwarfish answered 5/11, 2022 at 17:57 Comment(0)
D
14

Solution: H.B. comment showed me the right direction to push unsollicited price ticker updates the client.

api route: yahoo-finance-ticker +server.js

import YahooFinanceTicker from "yahoo-finance-ticker";

const ticker = new YahooFinanceTicker();
const tickerListener = await ticker.subscribe(["BTC-USD"])

/** @type {import('./$types').RequestHandler} */
export function GET({ request }) {
  const ac = new AbortController();

  console.log("GET api: yahoo-finance-ticker")
  const stream = new ReadableStream({
    start(controller) {
      tickerListener.on("ticker", (ticker) => {
        console.log(ticker.price);
        controller.enqueue(String(ticker.price));
      }, { signal: ac.signal });
    },
    cancel() {
      console.log("cancel and abort");
      ac.abort();
    },
  })

  return new Response(stream, {
    headers: {
      'content-type': 'text/event-stream',
    }
  });
}

page route: +page.svelte

<script>
  let result = "";

  async function getStream() {
    const response = await fetch("/api/yahoo-finance-ticker");
    const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
    while (true) {
      const { value, done } = await reader.read();
      console.log("resp", done, value);
      if (done) break;
      result += `${value}<br>`;
    }
  }

  getStream();
</script>

<section>
  <p>{@html result}</p>
</section>
Dwarfish answered 6/11, 2022 at 13:18 Comment(0)
M
4

To my knowledge, the load functions cannot be used for this as their responses are JS/JSON serialized. You can use an endpoint in +server to return a Response object which can be constructed from a ReadableStream.

Mullens answered 5/11, 2022 at 20:54 Comment(1)
OK. The +server example with the Readable stream note shows me the right direction.Dwarfish

© 2022 - 2024 — McMap. All rights reserved.