import type { EnvironmentId as EnvironmentIdType } from "@t3tools/contracts"; import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; import * as Stream from "effect/Stream"; import * as SubscriptionRef from "effect/SubscriptionRef"; import { AsyncResult, Atom } from "effect/unstable/reactivity"; import * as EnvironmentRegistry from "../connection/registry.ts"; import type { ConnectionCatalogEntry } from "../connection/catalog.ts"; import { AVAILABLE_CONNECTION_STATE } from "../connection/model.ts"; import * as EnvironmentSupervisor from "../connection/supervisor.ts"; import { createAtomCommandScheduler, createRuntimeCommand, followStreamInEnvironment, } from "./runtime.ts"; export interface EnvironmentCatalogState { readonly isReady: boolean; readonly entries: ReadonlyMap; } const EMPTY_ENVIRONMENT_CATALOG_STATE: EnvironmentCatalogState = Object.freeze({ isReady: false, entries: new Map(), }); export function createEnvironmentCatalogAtoms( runtime: Atom.AtomRuntime, ) { const commandScheduler = createAtomCommandScheduler(); const serial = { mode: "serial" as const, key: () => "environment-catalog" }; const catalogAtom = runtime.atom( Stream.unwrap( EnvironmentRegistry.EnvironmentRegistry.pipe( Effect.map((registry) => SubscriptionRef.changes(registry.entries).pipe( Stream.map((entries) => ({ isReady: true, entries, })), ), ), ), ), { initialValue: EMPTY_ENVIRONMENT_CATALOG_STATE }, ); const catalogValueAtom = Atom.make((get) => Option.getOrElse(AsyncResult.value(get(catalogAtom)), () => EMPTY_ENVIRONMENT_CATALOG_STATE), ).pipe(Atom.withLabel("environment-catalog-value")); const networkStatusAtom = runtime.atom( Stream.unwrap( EnvironmentRegistry.EnvironmentRegistry.pipe( Effect.map((registry) => SubscriptionRef.changes(registry.networkStatus)), ), ), { initialValue: "unknown" as const }, ); const networkStatusValueAtom = Atom.make((get) => Option.getOrElse(AsyncResult.value(get(networkStatusAtom)), () => "unknown" as const), ).pipe(Atom.withLabel("environment-network-status-value")); const stateAtom = Atom.family((environmentId: EnvironmentIdType) => runtime.atom( followStreamInEnvironment( environmentId, Stream.unwrap( EnvironmentSupervisor.EnvironmentSupervisor.pipe( Effect.map((supervisor) => SubscriptionRef.changes(supervisor.state)), ), ), ), { initialValue: AVAILABLE_CONNECTION_STATE }, ), ); const register = createRuntimeCommand(runtime, { label: "environment-catalog:register", scheduler: commandScheduler, concurrency: serial, execute: ( target: Parameters[0], ) => EnvironmentRegistry.EnvironmentRegistry.pipe( Effect.flatMap((registry) => registry.register(target)), ), }); const remove = createRuntimeCommand(runtime, { label: "environment-catalog:remove", scheduler: commandScheduler, concurrency: serial, execute: (environmentId: EnvironmentIdType) => EnvironmentRegistry.EnvironmentRegistry.pipe( Effect.flatMap((registry) => registry.remove(environmentId)), ), }); const removeRelayEnvironments = createRuntimeCommand(runtime, { label: "environment-catalog:remove-relay-environments", scheduler: commandScheduler, concurrency: serial, execute: (_input: void) => EnvironmentRegistry.EnvironmentRegistry.pipe( Effect.flatMap((registry) => registry.removeRelayEnvironments()), ), }); const retryNow = createRuntimeCommand(runtime, { label: "environment-catalog:retry-now", scheduler: commandScheduler, concurrency: serial, execute: (environmentId: EnvironmentIdType) => EnvironmentRegistry.EnvironmentRegistry.pipe( Effect.flatMap((registry) => registry.retryNow(environmentId)), ), }); return { catalogAtom, catalogValueAtom, networkStatusAtom, networkStatusValueAtom, stateAtom, register, remove, removeRelayEnvironments, retryNow, }; }