fix(backups): проверять ответы и прогресс резервного копирования
This commit is contained in:
1 parent
46fe38321a
commit
4ae2954f97
6 files changed
+189
-113
No files matched your search
+47
-106
@@ -1,122 +1,63 @@
|
||||
import { requestJson } from "@/shared/api/http-client"
|
||||
import type {
|
||||
BackupScheduleSettingsDto,
|
||||
BackupStorageSettingsDto,
|
||||
PutBackupStorageSettings,
|
||||
import {
|
||||
backupJobResponseSchema,
|
||||
backupScheduleSettingsDtoSchema,
|
||||
backupStorageSettingsDtoSchema,
|
||||
backupsListResponseSchema,
|
||||
createBackupJobResponseSchema,
|
||||
createBackupRequestSchema,
|
||||
putBackupScheduleSettingsSchema,
|
||||
putBackupStorageSettingsSchema,
|
||||
restoreBackupResponseSchema,
|
||||
syncBackupsResponseSchema,
|
||||
} from "@mmapp/contracts/backups"
|
||||
import type { BackupItemDto, BackupScheduleSettingsDto, PutBackupStorageSettings } from "@mmapp/contracts/backups"
|
||||
import { requestBlob, requestJson } from "@/shared/api/http-client"
|
||||
|
||||
export type BackupItem = {
|
||||
id: string
|
||||
serverId: number | string | null
|
||||
serverName: string
|
||||
filename: string
|
||||
sizeBytes: number
|
||||
createdAt: string
|
||||
kind: "manual" | "auto"
|
||||
notes?: string
|
||||
storage?: "local" | "s3" | "both"
|
||||
s3Key?: string | null
|
||||
uploadError?: string | null
|
||||
}
|
||||
export type BackupItem = BackupItemDto
|
||||
export type { CreateBackupJobResponse, BackupJobStatusResponse } from "@mmapp/contracts/backups"
|
||||
|
||||
type CreateBackupResponse = {
|
||||
created: BackupItem[]
|
||||
failures: Array<{ serverId: string; error: string }>
|
||||
function backupOptions(options?: RequestInit): RequestInit {
|
||||
return { ...options, signal: AbortSignal.any([...(options?.signal ? [options.signal] : []), AbortSignal.timeout(30_000)]) }
|
||||
}
|
||||
|
||||
export type CreateBackupJobResponse = {
|
||||
jobId: string
|
||||
status: "queued" | "running" | "done" | "failed"
|
||||
total: number
|
||||
completed: number
|
||||
function backupJson(baseUrl: string, path: string, options?: RequestInit) {
|
||||
return requestJson<unknown>(baseUrl, path, backupOptions(options))
|
||||
}
|
||||
|
||||
export type BackupJobStatusResponse = {
|
||||
id: string
|
||||
status: "queued" | "running" | "done" | "failed"
|
||||
requestedAt: string
|
||||
startedAt?: string
|
||||
finishedAt?: string
|
||||
total: number
|
||||
completed: number
|
||||
created: BackupItem[]
|
||||
failures: Array<{ serverId: string; error: string }>
|
||||
export async function listBackups(baseUrl: string, options?: RequestInit) {
|
||||
return backupsListResponseSchema.parse(await backupJson(baseUrl, "/api/backups", { ...options, method: "GET" }))
|
||||
}
|
||||
|
||||
export async function listBackups(baseUrl: string): Promise<BackupItem[]> {
|
||||
return requestJson<BackupItem[]>(baseUrl, "/api/backups")
|
||||
export async function createBackupsAsync(baseUrl: string, payload: { serverIds: string[]; notes?: string }, options?: RequestInit) {
|
||||
const body = createBackupRequestSchema.parse(payload)
|
||||
return createBackupJobResponseSchema.parse(await backupJson(baseUrl, "/api/backups/create", { ...options, method: "POST", body: JSON.stringify(body) }))
|
||||
}
|
||||
|
||||
export async function createBackups(
|
||||
baseUrl: string,
|
||||
payload: { serverIds: string[]; notes?: string },
|
||||
): Promise<CreateBackupResponse> {
|
||||
return requestJson<CreateBackupResponse>(baseUrl, "/api/backups/create", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
export async function getBackupJob(baseUrl: string, jobId: string, options?: RequestInit) {
|
||||
const result = backupJobResponseSchema.parse(await backupJson(baseUrl, "/api/backups/jobs/" + encodeURIComponent(jobId), { ...options, method: "GET" }))
|
||||
if (result.id !== jobId) throw new Error("Ответ относится к другой задаче резервного копирования")
|
||||
return result
|
||||
}
|
||||
|
||||
export async function createBackupsAsync(
|
||||
baseUrl: string,
|
||||
payload: { serverIds: string[]; notes?: string },
|
||||
): Promise<CreateBackupJobResponse> {
|
||||
return requestJson<CreateBackupJobResponse>(baseUrl, "/api/backups/create", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
export async function deleteBackup(baseUrl: string, id: string, options?: RequestInit): Promise<void> {
|
||||
const response = await requestBlob(baseUrl, "/api/backups/" + encodeURIComponent(id), backupOptions({ ...options, method: "DELETE" }))
|
||||
if (response.status !== 204) throw new Error("Удаление резервной копии не подтверждено: ожидается HTTP 204")
|
||||
}
|
||||
|
||||
export async function getBackupJob(baseUrl: string, jobId: string): Promise<BackupJobStatusResponse> {
|
||||
return requestJson<BackupJobStatusResponse>(baseUrl, `/api/backups/jobs/${jobId}`)
|
||||
export async function restoreBackup(baseUrl: string, id: string, options?: RequestInit) {
|
||||
return restoreBackupResponseSchema.parse(await backupJson(baseUrl, "/api/backups/" + encodeURIComponent(id) + "/restore", { ...options, method: "POST" }))
|
||||
}
|
||||
|
||||
export async function deleteBackup(baseUrl: string, id: string): Promise<void> {
|
||||
await requestJson<void>(baseUrl, `/api/backups/${id}`, { method: "DELETE" })
|
||||
export async function getBackupScheduleSettings(baseUrl: string, options?: RequestInit) {
|
||||
return backupScheduleSettingsDtoSchema.parse(await backupJson(baseUrl, "/api/backups/schedule", { ...options, method: "GET" }))
|
||||
}
|
||||
|
||||
export async function restoreBackup(baseUrl: string, id: string): Promise<{ filename: string; serverName: string }> {
|
||||
return requestJson<{ filename: string; serverName: string }>(baseUrl, `/api/backups/${id}/restore`, {
|
||||
method: "POST",
|
||||
})
|
||||
export async function putBackupScheduleSettings(baseUrl: string, payload: Partial<BackupScheduleSettingsDto>, options?: RequestInit) {
|
||||
const body = putBackupScheduleSettingsSchema.parse(payload)
|
||||
return backupScheduleSettingsDtoSchema.parse(await backupJson(baseUrl, "/api/backups/schedule", { ...options, method: "PUT", body: JSON.stringify(body) }))
|
||||
}
|
||||
|
||||
export async function getBackupScheduleSettings(baseUrl: string): Promise<BackupScheduleSettingsDto> {
|
||||
return requestJson<BackupScheduleSettingsDto>(baseUrl, "/api/backups/schedule")
|
||||
export async function getBackupStorageSettings(baseUrl: string, options?: RequestInit) {
|
||||
return backupStorageSettingsDtoSchema.parse(await backupJson(baseUrl, "/api/backups/storage", { ...options, method: "GET" }))
|
||||
}
|
||||
|
||||
export async function putBackupScheduleSettings(
|
||||
baseUrl: string,
|
||||
payload: Partial<BackupScheduleSettingsDto>,
|
||||
): Promise<BackupScheduleSettingsDto> {
|
||||
return requestJson<BackupScheduleSettingsDto>(baseUrl, "/api/backups/schedule", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
export async function putBackupStorageSettings(baseUrl: string, payload: PutBackupStorageSettings, options?: RequestInit) {
|
||||
const body = putBackupStorageSettingsSchema.parse(payload)
|
||||
return backupStorageSettingsDtoSchema.parse(await backupJson(baseUrl, "/api/backups/storage", { ...options, method: "PUT", body: JSON.stringify(body) }))
|
||||
}
|
||||
|
||||
export async function getBackupStorageSettings(baseUrl: string): Promise<BackupStorageSettingsDto> {
|
||||
return requestJson<BackupStorageSettingsDto>(baseUrl, "/api/backups/storage")
|
||||
export async function testBackupStorage(baseUrl: string, options?: RequestInit) {
|
||||
return backupStorageSettingsDtoSchema.parse(await backupJson(baseUrl, "/api/backups/storage/test", { ...options, method: "POST" }))
|
||||
}
|
||||
|
||||
export async function putBackupStorageSettings(
|
||||
baseUrl: string,
|
||||
payload: PutBackupStorageSettings,
|
||||
): Promise<BackupStorageSettingsDto> {
|
||||
return requestJson<BackupStorageSettingsDto>(baseUrl, "/api/backups/storage", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
}
|
||||
|
||||
export async function testBackupStorage(baseUrl: string): Promise<BackupStorageSettingsDto> {
|
||||
return requestJson<BackupStorageSettingsDto>(baseUrl, "/api/backups/storage/test", { method: "POST" })
|
||||
}
|
||||
|
||||
export async function syncBackupsFromStorage(
|
||||
baseUrl: string,
|
||||
): Promise<{ imported: number; skipped: number }> {
|
||||
return requestJson<{ imported: number; skipped: number }>(baseUrl, "/api/backups/storage/sync", {
|
||||
method: "POST",
|
||||
})
|
||||
export async function syncBackupsFromStorage(baseUrl: string, options?: RequestInit) {
|
||||
return syncBackupsResponseSchema.parse(await backupJson(baseUrl, "/api/backups/storage/sync", { ...options, method: "POST" }))
|
||||
}
|
||||
Reference in new issue
Block a user