Files

26 lines
2.7 KiB
TypeScript

import { z } from "zod"
import { geoipSettingsPatchSchema, geoipStatusDtoSchema, geoipUpdateSnapshotDtoSchema, type GeoipSettingsPatch } from "@mmapp/contracts/geoip"
import { requestJson } from "@/shared/api/http-client"
const statusSchema = geoipStatusDtoSchema.refine(status => status.ready === (status.countryLoaded && status.asnLoaded) && [status.settings.updatedAt, status.settings.lastCheckAt, status.settings.lastSuccessAt, status.settings.countryBuildAt, status.settings.asnBuildAt].every(value => value === null || Number.isFinite(Date.parse(value))), "Несогласованная готовность или время GeoIP")
const updateSchema = z.object({ ok: z.boolean(), snapshot: geoipUpdateSnapshotDtoSchema }).refine(response => response.snapshot.v === 1 && Number.isFinite(Date.parse(response.snapshot.sampledAt)) && response.snapshot.checked >= 0 && response.snapshot.downloaded >= 0 && response.snapshot.skippedUnchanged >= 0 && response.snapshot.downloaded + response.snapshot.skippedUnchanged <= response.snapshot.checked && response.ok === (!response.snapshot.fatalError && response.snapshot.errors.length === 0), "Несогласованный результат GeoIP")
function confirmed<T>(schema: z.ZodType<T>, raw: unknown): T {
const parsed = schema.safeParse(raw)
if (!parsed.success) throw new Error("Данные GeoIP не подтверждены: получен некорректный ответ сервера")
return parsed.data
}
async function json(baseUrl: string, path: string, init?: RequestInit) {
return requestJson<unknown>(baseUrl, path, { ...init, signal: AbortSignal.any([...(init?.signal ? [init.signal] : []), AbortSignal.timeout(30_000)]) })
}
export async function getGeoipStatus(baseUrl: string, init?: RequestInit) {
return confirmed(statusSchema, await json(baseUrl, "/api/geoip", { ...init, method: "GET" }))
}
export async function putGeoipSettings(baseUrl: string, patch: GeoipSettingsPatch, init?: RequestInit) {
const body = geoipSettingsPatchSchema.strict().parse(patch)
const response = confirmed(z.object({ ok: z.literal(true), status: statusSchema }), await json(baseUrl, "/api/geoip", { ...init, method: "PUT", body: JSON.stringify(body) }))
for (const field of ["enabled", "updateIntervalSec"] as const) if (body[field] !== undefined && body[field] !== response.status.settings[field]) throw new Error("Сохранение настроек GeoIP не подтверждено: ответ отличается от отправленных значений")
return response
}
export async function runGeoipUpdateNow(baseUrl: string, init?: RequestInit) {
return confirmed(updateSchema, await json(baseUrl, "/api/geoip/update", { ...init, method: "POST" }))
}