fix(ui): сохранять достоверные снимки сертификатов
This commit is contained in:
1 parent
17f03e7af1
commit
b184922f61
7 files changed
+242
-93
No files matched your search
@@ -0,0 +1,61 @@
|
||||
"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 }
|
||||
}
|
||||
Reference in new issue
Block a user