备份与恢复
This commit is contained in:
1 parent
5d5fecde1b
commit
b4535d6aea
6 files changed
+252
-27
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import { createReadStream, promises as fs } from 'node:fs'
|
||||
import { join, relative } from 'node:path'
|
||||
import { pipeline } from 'node:stream/promises'
|
||||
import { DatabaseSync } from 'node:sqlite'
|
||||
import * as tar from 'tar'
|
||||
import { getImageIndexRow } from '../image-index'
|
||||
import { getActiveBackend } from '../storage/resolver'
|
||||
@@ -48,32 +49,53 @@ async function readManifest(stagingRoot: string): Promise<BackupManifest> {
|
||||
return manifest
|
||||
}
|
||||
|
||||
interface RestoreImageRow {
|
||||
key: string
|
||||
thumb_key: string | null
|
||||
hls_key: string | null
|
||||
source_deleted: number
|
||||
}
|
||||
|
||||
function readRestoreImageRows(stagingRoot: string): RestoreImageRow[] {
|
||||
const db = new DatabaseSync(
|
||||
join(stagingRoot, 'database', 'pichost.sqlite'),
|
||||
{ readOnly: true }
|
||||
)
|
||||
try {
|
||||
return db.prepare(`
|
||||
SELECT key, thumb_key, hls_key, source_deleted
|
||||
FROM images
|
||||
`).all() as unknown as RestoreImageRow[]
|
||||
} finally {
|
||||
db.close()
|
||||
}
|
||||
}
|
||||
|
||||
export async function previewFullRestore(archivePath: string): Promise<BackupRestorePreview> {
|
||||
const stagingRoot = getBackupStagingDir(`preview-${Date.now()}`)
|
||||
try {
|
||||
await extractArchive(archivePath, stagingRoot)
|
||||
const manifest = await readManifest(stagingRoot)
|
||||
const blobsRoot = join(stagingRoot, 'blobs')
|
||||
let blobFiles: string[] = []
|
||||
try {
|
||||
blobFiles = await walkFiles(blobsRoot)
|
||||
} catch {
|
||||
blobFiles = []
|
||||
}
|
||||
|
||||
const backend = await getActiveBackend()
|
||||
const imageRows = readRestoreImageRows(stagingRoot)
|
||||
let conflictingImages = 0
|
||||
for (const file of blobFiles) {
|
||||
const rel = relative(blobsRoot, file).replace(/\\/g, '/')
|
||||
if (await backend.head(rel)) {
|
||||
for (const row of imageRows) {
|
||||
const keys = [
|
||||
...(Number(row.source_deleted) === 1 ? [] : [row.key]),
|
||||
...(row.thumb_key ? [row.thumb_key] : []),
|
||||
...(row.hls_key ? [row.hls_key] : [])
|
||||
]
|
||||
for (const key of keys) {
|
||||
if (!await backend.head(key)) continue
|
||||
conflictingImages += 1
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
imageCount: manifest.imageCount,
|
||||
imageCount: imageRows.length,
|
||||
imageBytes: manifest.imageBytes,
|
||||
newImages: Math.max(0, blobFiles.length - conflictingImages),
|
||||
newImages: imageRows.length - conflictingImages,
|
||||
conflictingImages,
|
||||
formatVersion: manifest.formatVersion,
|
||||
appVersion: manifest.appVersion,
|
||||
|
||||
Reference in new issue
Block a user