voscausa
voscausa

Reputation: 11706

How to respond with a stream in a Sveltekit server load function

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.

Upvotes: 6

Views: 6175

Answers (2)

voscausa
voscausa

Reputation: 11706

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>

Upvotes: 14

brunnerh
brunnerh

Reputation: 184737

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.

Upvotes: 4

Related Questions