| 1 | import { useAtomValue } from "@effect/atom-react"; |
| 2 | import { |
| 3 | RelayConnectionRegistration, |
| 4 | RelayConnectionTarget, |
| 5 | } from "@t3tools/client-runtime/connection"; |
| 6 | import type { EnvironmentId } from "@t3tools/contracts"; |
| 7 | import type { |
| 8 | RelayClientEnvironmentRecord, |
| 9 | RelayEnvironmentStatusResponse, |
| 10 | } from "@t3tools/contracts/relay"; |
| 11 | import * as Option from "effect/Option"; |
| 12 | import { useCallback, useMemo } from "react"; |
| 13 | |
| 14 | import { environmentCatalog } from "../../connection/catalog"; |
| 15 | import { |
| 16 | connectPairingUrl as connectPairingUrlAtom, |
| 17 | updateBearerConnection, |
| 18 | } from "../../connection/onboarding"; |
| 19 | import { useWorkspaceEnvironments } from "../../state/workspace"; |
| 20 | import { relayEnvironmentDiscovery } from "../../state/relay"; |
| 21 | import { useAtomCommand } from "../../state/use-atom-command"; |
| 22 | import { relayManagedEnvironmentIds } from "./environmentSections"; |
| 23 | |
| 24 | export interface RelayEnvironmentView { |
| 25 | readonly environment: RelayClientEnvironmentRecord; |
| 26 | readonly availability: "checking" | "online" | "offline" | "error"; |
| 27 | readonly status: RelayEnvironmentStatusResponse | null; |
| 28 | readonly error: string | null; |
| 29 | readonly traceId: string | null; |
| 30 | } |
| 31 | |
| 32 | export function useConnectionController() { |
| 33 | const connectedEnvironments = useWorkspaceEnvironments(); |
| 34 | const discovery = useAtomValue(relayEnvironmentDiscovery.stateValueAtom); |
| 35 | const connectPairingUrlMutation = useAtomCommand(connectPairingUrlAtom, { |
| 36 | reportFailure: false, |
| 37 | }); |
| 38 | const updateBearer = useAtomCommand(updateBearerConnection, { reportFailure: false }); |
| 39 | const registerEnvironment = useAtomCommand(environmentCatalog.register, "environment register"); |
| 40 | const removeEnvironmentMutation = useAtomCommand(environmentCatalog.remove, "environment remove"); |
| 41 | const retryEnvironmentMutation = useAtomCommand(environmentCatalog.retryNow, "environment retry"); |
| 42 | const setEnvironmentEnabledMutation = useAtomCommand( |
| 43 | environmentCatalog.setEnabled, |
| 44 | "environment toggle", |
| 45 | ); |
| 46 | const refreshRelayEnvironments = useAtomCommand( |
| 47 | relayEnvironmentDiscovery.refresh, |
| 48 | "relay environment refresh", |
| 49 | ); |
| 50 | |
| 51 | const registeredIds = useMemo( |
| 52 | () => relayManagedEnvironmentIds(connectedEnvironments), |
| 53 | [connectedEnvironments], |
| 54 | ); |
| 55 | const relayEnvironments = useMemo<ReadonlyArray<RelayEnvironmentView>>( |
| 56 | () => |
| 57 | [...discovery.environments.values()].map((entry) => ({ |
| 58 | environment: entry.environment, |
| 59 | availability: entry.availability, |
| 60 | status: Option.getOrNull(entry.status), |
| 61 | error: Option.getOrNull(entry.error)?.message ?? null, |
| 62 | traceId: Option.getOrNull(entry.error)?.traceId ?? null, |
| 63 | })), |
| 64 | [discovery.environments], |
| 65 | ); |
| 66 | const availableRelayEnvironments = useMemo( |
| 67 | () => relayEnvironments.filter((entry) => !registeredIds.has(entry.environment.environmentId)), |
| 68 | [registeredIds, relayEnvironments], |
| 69 | ); |
| 70 | |
| 71 | const connectPairingUrl = useCallback( |
| 72 | (pairingUrl: string, expectedEnvironmentId?: EnvironmentId) => |
| 73 | connectPairingUrlMutation({ |
| 74 | pairingUrl, |
| 75 | ...(expectedEnvironmentId === undefined ? {} : { expectedEnvironmentId }), |
| 76 | }), |
| 77 | [connectPairingUrlMutation], |
| 78 | ); |
| 79 | const connectRelayEnvironment = useCallback( |
| 80 | (environment: RelayClientEnvironmentRecord) => |
| 81 | registerEnvironment( |
| 82 | new RelayConnectionRegistration({ |
| 83 | target: new RelayConnectionTarget({ |
| 84 | environmentId: environment.environmentId, |
| 85 | label: environment.label, |
| 86 | }), |
| 87 | }), |
| 88 | ), |
| 89 | [registerEnvironment], |
| 90 | ); |
| 91 | const removeEnvironment = useCallback( |
| 92 | (environmentId: EnvironmentId) => removeEnvironmentMutation(environmentId), |
| 93 | [removeEnvironmentMutation], |
| 94 | ); |
| 95 | const retryEnvironment = useCallback( |
| 96 | (environmentId: EnvironmentId) => retryEnvironmentMutation(environmentId), |
| 97 | [retryEnvironmentMutation], |
| 98 | ); |
| 99 | const setEnvironmentEnabled = useCallback( |
| 100 | (environmentId: EnvironmentId, enabled: boolean) => |
| 101 | setEnvironmentEnabledMutation({ environmentId, enabled }), |
| 102 | [setEnvironmentEnabledMutation], |
| 103 | ); |
| 104 | const updateEnvironment = useCallback( |
| 105 | ( |
| 106 | environmentId: EnvironmentId, |
| 107 | updates: { readonly label: string; readonly displayUrl: string }, |
| 108 | ) => |
| 109 | updateBearer({ |
| 110 | environmentId, |
| 111 | label: updates.label, |
| 112 | httpBaseUrl: updates.displayUrl, |
| 113 | }), |
| 114 | [updateBearer], |
| 115 | ); |
| 116 | |
| 117 | return { |
| 118 | connectedEnvironments, |
| 119 | relayEnvironments, |
| 120 | availableRelayEnvironments, |
| 121 | relayDiscovery: { |
| 122 | isRefreshing: discovery.refreshing, |
| 123 | isOffline: discovery.offline, |
| 124 | error: Option.getOrNull(discovery.error)?.message ?? null, |
| 125 | errorTraceId: Option.getOrNull(discovery.error)?.traceId ?? null, |
| 126 | }, |
| 127 | connectPairingUrl, |
| 128 | connectRelayEnvironment, |
| 129 | removeEnvironment, |
| 130 | retryEnvironment, |
| 131 | setEnvironmentEnabled, |
| 132 | updateEnvironment, |
| 133 | refreshRelayEnvironments, |
| 134 | }; |
| 135 | } |