Skip to content
Source
Sign inSign up
Open History to see the last commit

previewStream.ts

72 lines2.6 KB

1import { useAtomValue } from "@effect/atom-react";
2import { PREVIEW_STREAM_BASE_PATH } from "@t3tools/client-runtime/preview/server-browser-stream";
3import {
4 type DeviceHubAccess,
5 resolveDeviceHubAccess,
6} from "@t3tools/client-runtime/state/deviceHubAccess";
7import type { EnvironmentId } from "@t3tools/contracts";
8import * as Effect from "effect/Effect";
9import * as Option from "effect/Option";
10import { AsyncResult, Atom, AtomRegistry } from "effect/reactivity";
11​
12import { connectionAtomRuntime } from "../connection/runtime";
13import { appAtomRegistry } from "../rpc/atomRegistry";
14import { environmentSession } from "./session";
15​
16const ACCESS_RETRY_INTERVAL_MS = 10_000;
17​
18const previewStreamAccessAtom = Atom.family((environmentId: EnvironmentId) =>
19 connectionAtomRuntime
20 .atom((get) => {
21 const prepared = Option.getOrNull(
22 get(environmentSession.preparedConnectionValueAtom(environmentId)),
23 );
24 if (prepared === null) return Effect.never;
25 return resolveDeviceHubAccess({ prepared, hubBasePath: PREVIEW_STREAM_BASE_PATH });
26 })
27 .pipe(Atom.setIdleTTL(60_000), Atom.withLabel(`preview-stream-access:${environmentId}`)),
28);
29​
30// Only a surface the user is looking at retries a failed lookup; one-shot readers such as
31// picture-in-picture see the failure at once.
32const retryingPreviewStreamAccessAtom = Atom.family((environmentId: EnvironmentId) =>
33 Atom.make((get) => {
34 const access = previewStreamAccessAtom(environmentId);
35 const result = get(access);
36 if (AsyncResult.isFailure(result)) {
37 const timer = setTimeout(() => get.refresh(access), ACCESS_RETRY_INTERVAL_MS);
38 get.addFinalizer(() => clearTimeout(timer));
39 }
40 return result;
41 }),
42);
43​
44export function usePreviewStreamAccess(
45 environmentId: EnvironmentId,
46 options?: { readonly retry: boolean },
47): DeviceHubAccess | null {
48 const result = useAtomValue(
49 options?.retry
50 ? retryingPreviewStreamAccessAtom(environmentId)
51 : previewStreamAccessAtom(environmentId),
52 );
53 return AsyncResult.isSuccess(result) ? result.value : null;
55​
56export function refreshPreviewStreamAccess(environmentId: EnvironmentId): void {
57 appAtomRegistry.refresh(previewStreamAccessAtom(environmentId));
59​
60export function readPreviewStreamAccess(
61 environmentId: EnvironmentId,
62 refresh: boolean,
63): Promise<DeviceHubAccess | null> {
64 const atom = previewStreamAccessAtom(environmentId);
65 if (refresh) appAtomRegistry.refresh(atom);
66 return Effect.runPromise(
67 AtomRegistry.getResult(appAtomRegistry, atom, { suspendOnWaiting: true }).pipe(
68 Effect.timeout("10 seconds"),
69 Effect.orElseSucceed(() => null),
70 ),
71 );