// import posthog from "posthog-js"; import { Modal } from "@nestri/ui"; import { useLocation } from "@builder.io/qwik-city"; import { Keyboard, Mouse, WebRTCStream } from "@nestri/input" import { $, component$, noSerialize, type NoSerialize, useSignal, useStore, useVisibleTask$ } from "@builder.io/qwik"; // import Nestri from "@nestri/sdk"; //TODO: go full screen, then lock on "landscape" screen-orientation on mobile // FIXME: Add authentication and authorization // export const getUserSubscriptions = server$( // async function () { // const access = this.cookie.get("access_token") // if (access) { // const bearerToken = access.value // const nestriClient = new Nestri({ bearerToken, maxRetries: 5 }) // const subscriptions = await nestriClient.users.session() // return subscriptions as "Free" | "Pro" // } // } // ); type PlayState = { nestriMouse: NoSerialize nestriKeyboard: NoSerialize webrtc: NoSerialize nestriLock?: boolean hasStream?: boolean showOffline?: boolean video?: HTMLVideoElement inputInitialized?: boolean initializedVideo?: boolean } export default component$(() => { const id = useLocation().params.id; const showBannerModal = useSignal(false) const showButtonModal = useSignal(false) const canvas = useSignal(); const playState = useStore({ nestriMouse: undefined, nestriKeyboard: undefined, nestriLock: undefined, webrtc: undefined, video: undefined, hasStream: undefined, showOffline: undefined, inputInitialized: false, initializedVideo: false }) const initializeInputDevices = $(() => { if (!canvas.value || !playState.webrtc || playState.inputInitialized) return; try { playState.nestriMouse = noSerialize(new Mouse({ canvas: canvas.value, webrtc: playState.webrtc })); playState.nestriKeyboard = noSerialize(new Keyboard({ canvas: canvas.value, webrtc: playState.webrtc })); playState.inputInitialized = true; console.log("Input devices initialized successfully"); } catch (error) { console.error("Failed to initialize input devices:", error); playState.inputInitialized = false; } }); const lockPlay = $(async () => { if (!canvas.value || !playState.hasStream || playState.nestriLock) return; try { await canvas.value.requestPointerLock(); await canvas.value.requestFullscreen(); if (document.fullscreenElement !== null) { if ('keyboard' in navigator && 'lock' in (navigator.keyboard as any)) { const keys = [ "AltLeft", "AltRight", "Tab", "Escape", "ContextMenu", "MetaLeft", "MetaRight" ]; try { await (navigator.keyboard as any).lock(keys); playState.nestriLock = true; console.log("Keyboard lock acquired"); } catch (e) { console.warn("Keyboard lock failed:", e); playState.nestriLock = false; } } } } catch (error) { console.error("Error during lock sequence:", error); } }); const setupPointerLockListener = $(() => { document.addEventListener("pointerlockchange", () => { if (!canvas.value) return; if (document.pointerLockElement === canvas.value) { // Initialize input devices when pointer is locked if (!playState.inputInitialized) { initializeInputDevices(); } } else { if (!showBannerModal.value) { const playing = sessionStorage.getItem("showedBanner"); showBannerModal.value = !playing || playing !== "true"; showButtonModal.value = playing === "true"; } // Clean up input devices if (playState.nestriKeyboard) { playState.nestriKeyboard.dispose(); playState.nestriKeyboard = undefined; } if (playState.nestriMouse) { playState.nestriMouse.dispose(); playState.nestriMouse = undefined; } playState.nestriLock = undefined; playState.inputInitialized = false; } }); }); const handleVideoInput = $(async () => { if (!playState.video) return; if (playState.initializedVideo) return; await playState.video.play().then(() => { if (canvas.value && playState.video) { canvas.value.width = playState.video.videoWidth; canvas.value.height = playState.video.videoHeight; playState.initializedVideo = true const ctx = canvas.value.getContext("2d"); const renderer = () => { if (ctx && playState.hasStream && playState.video) { ctx.drawImage(playState.video, 0, 0); playState.video.requestVideoFrameCallback(renderer); } }; playState.video.requestVideoFrameCallback(renderer); } }).catch(error => { console.error("Error playing video:", error); }); }); // eslint-disable-next-line qwik/no-use-visible-task useVisibleTask$(({ track }) => { track(() => canvas.value); if (!canvas.value) return; // Ensure canvas is available // Get query parameter "peerURL" from the URL let peerURL = new URLSearchParams(window.location.search).get("peerURL"); if (!peerURL || peerURL.length <= 0) { peerURL = "/dnsaddr/relay.dathorse.com/p2p/12D3KooWPK4v5wKYNYx9oXWjqLM8Xix6nm13o91j1Feqq98fLBsw"; } setupPointerLockListener(); try { if (!playState.video) { playState.video = document.createElement("video") as HTMLVideoElement; playState.video.style.visibility = "hidden"; playState.webrtc = noSerialize(new WebRTCStream(peerURL, id, async (mediaStream) => { if (playState.video && mediaStream && playState.video.srcObject === null) { console.log("Setting mediastream"); playState.video.srcObject = mediaStream; playState.hasStream = true; playState.showOffline = false; const playing = sessionStorage.getItem("showedBanner") if (!playing || playing != "true") { if (!showBannerModal.value) showBannerModal.value = true } else { if (!showButtonModal.value) showButtonModal.value = true } await handleVideoInput(); } else if (mediaStream === null) { console.log("MediaStream is null, Room is offline"); playState.showOffline = true playState.hasStream = false; // Clear canvas if it has been set if (canvas.value) { const ctx = canvas.value.getContext("2d"); if (ctx) ctx.clearRect(0, 0, canvas.value.width, canvas.value.height); } } else if (playState.video && playState.video.srcObject !== null) { console.log("Setting new mediastream"); playState.video.srcObject = mediaStream; playState.hasStream = true; playState.showOffline = true playState.video.play().then(() => { // window.roomOfflineElement?.remove(); playState.showOffline = false if (canvas.value && playState.video) { canvas.value.width = playState.video.videoWidth; canvas.value.height = playState.video.videoHeight; const ctx = canvas.value.getContext("2d"); const renderer = () => { if (ctx && playState.hasStream && playState.video) { ctx.drawImage(playState.video, 0, 0); playState.video.requestVideoFrameCallback(renderer); } } playState.video.requestVideoFrameCallback(renderer); } }); } })); } } catch (error) { console.log("error handling the media connection", error) } }) return ( <> {playState.showOffline ? (
Offline
) : ( <> < canvas ref={canvas} onClick$={lockPlay} class="aspect-video h-full w-full object-contain max-h-screen" /> {typeof playState.showOffline === "undefined" && (
{new Array(12).fill(0).map((i, k) => (
))}
Warming up the GPU...
)} )}

Important information from Nestri

This product is in Alpha — please share feedback whenever possible to help us improve. Thanks you for your support! 💖
) })