Files
MikrotikManager/lib/use-certificate-catalog.ts
T

62 lines
2.8 KiB
TypeScript

"use client"
import { useCallback, useEffect, useRef, useState } from "react"
import { serverListSchema, type ServerRead } from "@mmapp/contracts/servers"
import { readCertificatesState } from "@/shared/api/certificates"
import { requestJson } from "@/shared/api/http-client"
import { mergeCertificateSnapshots, type CertificateSnapshots } from "@/lib/certificate-snapshots"
export function useCertificateCatalog(backendUrl: string, live: boolean, canRead: boolean, canReadServers: boolean) {
const [snapshots, setSnapshots] = useState<CertificateSnapshots>({})
const [servers, setServers] = useState<ServerRead[]>([])
const [hasState, setHasState] = useState(false)
const [hasServers, setHasServers] = useState(false)
const [loading, setLoading] = useState(live)
const [error, setError] = useState<string | null>(null)
const [serverError, setServerError] = useState<string | null>(null)
const [collectedAt, setCollectedAt] = useState<string | null>(null)
const controller = useRef<AbortController | null>(null)
const revision = useRef(0)
const alive = useRef(true)
const reload = useCallback(async () => {
if (!live || !alive.current) return
controller.current?.abort()
const current = ++revision.current
const abort = new AbortController()
controller.current = abort
const signal = AbortSignal.any([abort.signal, AbortSignal.timeout(30_000)])
const active = () => alive.current && !abort.signal.aborted && revision.current === current
setLoading(true)
await Promise.allSettled([
canRead ? readCertificatesState(backendUrl, { signal }).then(result => {
if (!active()) return
setSnapshots(previous => mergeCertificateSnapshots(previous, result))
setHasState(true)
setCollectedAt(result.collectedAt)
setError(null)
}).catch(reason => {
if (active()) setError(reason instanceof Error ? reason.message : "Ошибка каталога сертификатов")
}) : Promise.resolve(),
canReadServers ? requestJson<unknown>(backendUrl, "/api/servers", { signal }).then(payload => {
const result = serverListSchema.parse(payload)
if (!active()) return
setServers(result)
setHasServers(true)
setServerError(null)
}).catch(reason => {
if (active()) setServerError(reason instanceof Error ? reason.message : "Ошибка каталога серверов")
}) : Promise.resolve(),
])
if (active()) setLoading(false)
}, [backendUrl, live, canRead, canReadServers])
useEffect(() => {
alive.current = true
queueMicrotask(() => { if (alive.current) void reload() })
return () => { alive.current = false; controller.current?.abort() }
}, [reload])
return { snapshots, servers, hasState, hasServers, loading, error, serverError, collectedAt, reload }
}