From 3c3955017e065005cec9ca9d6d422ba064b58d65 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 4 May 2024 10:49:33 +0530 Subject: [PATCH] Start chromecast SDK only once --- web/apps/cast/src/pages/index.tsx | 12 ++++---- web/apps/cast/src/services/pair.ts | 2 +- web/apps/cast/src/utils/cast-receiver.tsx | 32 +++++++++++++++++++++ web/apps/cast/src/utils/useCastReceiver.tsx | 25 ---------------- 4 files changed, 38 insertions(+), 33 deletions(-) create mode 100644 web/apps/cast/src/utils/cast-receiver.tsx delete mode 100644 web/apps/cast/src/utils/useCastReceiver.tsx diff --git a/web/apps/cast/src/pages/index.tsx b/web/apps/cast/src/pages/index.tsx index a9d581206..87ce756e0 100644 --- a/web/apps/cast/src/pages/index.tsx +++ b/web/apps/cast/src/pages/index.tsx @@ -5,17 +5,13 @@ import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import { storeCastData } from "services/cast"; import { advertiseCode, getCastData, register } from "services/pair"; -import { useCastReceiver } from "../utils/useCastReceiver"; +import { castReceiverLoadingIfNeeded } from "../utils/cast-receiver"; export default function PairingMode() { const [publicKeyB64, setPublicKeyB64] = useState(); const [privateKeyB64, setPrivateKeyB64] = useState(); const [pairingCode, setPairingCode] = useState(); - // The returned cast object is a reference to a global instance and can be - // used in a useEffect dependency list. - const cast = useCastReceiver(); - const router = useRouter(); const init = () => { @@ -31,8 +27,10 @@ export default function PairingMode() { }, []); useEffect(() => { - if (cast) advertiseCode(cast, () => pairingCode); - }, [cast]); + castReceiverLoadingIfNeeded().then((cast) => + advertiseCode(cast, () => pairingCode), + ); + }, []); const pollTick = async () => { const registration = { publicKeyB64, privateKeyB64, pairingCode }; diff --git a/web/apps/cast/src/services/pair.ts b/web/apps/cast/src/services/pair.ts index f0bff7787..31419927d 100644 --- a/web/apps/cast/src/services/pair.ts +++ b/web/apps/cast/src/services/pair.ts @@ -3,7 +3,7 @@ import { boxSealOpen, toB64 } from "@ente/shared/crypto/internal/libsodium"; import castGateway from "@ente/shared/network/cast"; import { wait } from "@ente/shared/utils"; import _sodium from "libsodium-wrappers"; -import { type Cast } from "../utils/useCastReceiver"; +import { type Cast } from "../utils/cast-receiver"; export interface Registration { /** A pairing code shown on the screen. A client can use this to connect. */ diff --git a/web/apps/cast/src/utils/cast-receiver.tsx b/web/apps/cast/src/utils/cast-receiver.tsx new file mode 100644 index 000000000..666a085ed --- /dev/null +++ b/web/apps/cast/src/utils/cast-receiver.tsx @@ -0,0 +1,32 @@ +/// + +export type Cast = typeof cast; + +let _cast: Cast | undefined; +let _loader: Promise | undefined; + +/** + * Load the Chromecast Web Receiver SDK and return a reference to the `cast` + * global object that the SDK attaches to the window. + * + * Calling this function multiple times is fine, once the Chromecast SDK is + * loaded it'll thereafter return the reference to the same object always. + * + * https://developers.google.com/cast/docs/web_receiver/basic + */ +export const castReceiverLoadingIfNeeded = async (): Promise => { + if (_cast) return _cast; + if (_loader) return await _loader; + + _loader = new Promise((resolve) => { + const script = document.createElement("script"); + script.src = + "https://www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"; + + script.addEventListener("load", () => resolve(cast)); + document.body.appendChild(script); + }); + const c = await _loader; + _cast = c; + return c; +}; diff --git a/web/apps/cast/src/utils/useCastReceiver.tsx b/web/apps/cast/src/utils/useCastReceiver.tsx deleted file mode 100644 index 8cd958ec4..000000000 --- a/web/apps/cast/src/utils/useCastReceiver.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/// -import { useEffect, useState } from "react"; - -export type Cast = typeof cast; - -/** - * Load the Chromecast Web Receiver SDK and return a reference to the `cast` - * global object that the SDK attaches to the window. - * - * https://developers.google.com/cast/docs/web_receiver/basic - */ -export const useCastReceiver = () => { - const [receiver, setReceiver] = useState(); - - useEffect(() => { - const script = document.createElement("script"); - script.src = - "https://www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"; - - script.addEventListener("load", () => setReceiver(cast)); - document.body.appendChild(script); - }, []); - - return receiver; -};