mirror of
https://github.com/immich-app/immich.git
synced 2025-12-20 17:25:35 +03:00
refactor: scope util to database-backups instead of backups
This commit is contained in:
@@ -26,8 +26,14 @@ import { type BaseService as _BaseService } from 'src/services/base.service';
|
||||
import { type DatabaseBackupService as _DatabaseBackupService } from 'src/services/database-backup.service';
|
||||
import { type ServerService as _ServerService } from 'src/services/server.service';
|
||||
import { MaintenanceModeState } from 'src/types';
|
||||
import { deleteBackups, downloadBackup, listBackups, restoreBackup, uploadBackup } from 'src/utils/backups';
|
||||
import { getConfig } from 'src/utils/config';
|
||||
import {
|
||||
deleteDatabaseBackup,
|
||||
downloadDatabaseBackup,
|
||||
listDatabaseBackups,
|
||||
restoreDatabaseBackup,
|
||||
uploadDatabaseBackup,
|
||||
} from 'src/utils/database-backups';
|
||||
import { ImmichFileResponse } from 'src/utils/file';
|
||||
import { createMaintenanceLoginUrl, detectPriorInstall } from 'src/utils/maintenance';
|
||||
import { getExternalDomain } from 'src/utils/misc';
|
||||
@@ -171,28 +177,28 @@ export class MaintenanceWorkerService {
|
||||
* {@link _DatabaseBackupService.listBackups}
|
||||
*/
|
||||
async listBackups(): Promise<{ backups: string[] }> {
|
||||
return { backups: await listBackups(this.backupRepos) };
|
||||
return { backups: await listDatabaseBackups(this.backupRepos) };
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link _DatabaseBackupService.deleteBackup}
|
||||
*/
|
||||
async deleteBackup(files: string[]): Promise<void> {
|
||||
return deleteBackups(this.backupRepos, files);
|
||||
return deleteDatabaseBackup(this.backupRepos, files);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link _DatabaseBackupService.uploadBackup}
|
||||
*/
|
||||
async uploadBackup(file: Express.Multer.File): Promise<void> {
|
||||
return uploadBackup(this.backupRepos, file);
|
||||
return uploadDatabaseBackup(this.backupRepos, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link _DatabaseBackupService.downloadBackup}
|
||||
*/
|
||||
downloadBackup(fileName: string): ImmichFileResponse {
|
||||
return downloadBackup(fileName);
|
||||
return downloadDatabaseBackup(fileName);
|
||||
}
|
||||
|
||||
private get backupRepos() {
|
||||
@@ -339,7 +345,7 @@ export class MaintenanceWorkerService {
|
||||
progress: 0,
|
||||
});
|
||||
|
||||
await restoreBackup(this.backupRepos, filename, (task, progress) =>
|
||||
await restoreDatabaseBackup(this.backupRepos, filename, (task, progress) =>
|
||||
this.setStatus({
|
||||
active: true,
|
||||
action: MaintenanceAction.RestoreDatabase,
|
||||
|
||||
@@ -6,11 +6,11 @@ import { DatabaseLock, ImmichWorker, JobName, JobStatus, QueueName, StorageFolde
|
||||
import { ArgOf } from 'src/repositories/event.repository';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import {
|
||||
createBackup,
|
||||
isFailedBackupName,
|
||||
isValidRoutineBackupName,
|
||||
createDatabaseBackup,
|
||||
isFailedDatabaseBackupName,
|
||||
isValidDatabaseRoutineBackupName,
|
||||
UnsupportedPostgresError,
|
||||
} from 'src/utils/backups';
|
||||
} from 'src/utils/database-backups';
|
||||
import { handlePromiseError } from 'src/utils/misc';
|
||||
|
||||
@Injectable()
|
||||
@@ -57,10 +57,10 @@ export class BackupService extends BaseService {
|
||||
const backupsFolder = StorageCore.getBaseFolder(StorageFolder.Backups);
|
||||
const files = await this.storageRepository.readdir(backupsFolder);
|
||||
const backups = files
|
||||
.filter((fn) => isValidRoutineBackupName(fn))
|
||||
.filter((fn) => isValidDatabaseRoutineBackupName(fn))
|
||||
.toSorted()
|
||||
.toReversed();
|
||||
const failedBackups = files.filter((fn) => isFailedBackupName(fn));
|
||||
const failedBackups = files.filter((fn) => isFailedDatabaseBackupName(fn));
|
||||
|
||||
const toDelete = backups.slice(config.keepLastAmount);
|
||||
toDelete.push(...failedBackups);
|
||||
@@ -74,7 +74,7 @@ export class BackupService extends BaseService {
|
||||
@OnJob({ name: JobName.DatabaseBackup, queue: QueueName.BackupDatabase })
|
||||
async handleBackupDatabase(): Promise<JobStatus> {
|
||||
try {
|
||||
await createBackup(this.backupRepos);
|
||||
await createDatabaseBackup(this.backupRepos);
|
||||
} catch (error) {
|
||||
if (error instanceof UnsupportedPostgresError) {
|
||||
return JobStatus.Failed;
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import { deleteBackups, downloadBackup, listBackups, uploadBackup } from 'src/utils/backups';
|
||||
import {
|
||||
deleteDatabaseBackup,
|
||||
downloadDatabaseBackup,
|
||||
listDatabaseBackups,
|
||||
uploadDatabaseBackup,
|
||||
} from 'src/utils/database-backups';
|
||||
import { ImmichFileResponse } from 'src/utils/file';
|
||||
|
||||
/**
|
||||
@@ -9,19 +14,19 @@ import { ImmichFileResponse } from 'src/utils/file';
|
||||
@Injectable()
|
||||
export class DatabaseBackupService extends BaseService {
|
||||
async listBackups(): Promise<{ backups: string[] }> {
|
||||
return { backups: await listBackups(this.backupRepos) };
|
||||
return { backups: await listDatabaseBackups(this.backupRepos) };
|
||||
}
|
||||
|
||||
deleteBackup(files: string[]): Promise<void> {
|
||||
return deleteBackups(this.backupRepos, files);
|
||||
return deleteDatabaseBackup(this.backupRepos, files);
|
||||
}
|
||||
|
||||
async uploadBackup(file: Express.Multer.File): Promise<void> {
|
||||
return uploadBackup(this.backupRepos, file);
|
||||
return uploadDatabaseBackup(this.backupRepos, file);
|
||||
}
|
||||
|
||||
downloadBackup(fileName: string): ImmichFileResponse {
|
||||
return downloadBackup(fileName);
|
||||
return downloadDatabaseBackup(fileName);
|
||||
}
|
||||
|
||||
private get backupRepos() {
|
||||
|
||||
@@ -14,18 +14,18 @@ import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { ProcessRepository } from 'src/repositories/process.repository';
|
||||
import { StorageRepository } from 'src/repositories/storage.repository';
|
||||
|
||||
export function isValidBackupName(filename: string) {
|
||||
export function isValidDatabaseBackupName(filename: string) {
|
||||
return filename.match(/^[\d\w-.]+\.sql(?:\.gz)?$/);
|
||||
}
|
||||
|
||||
export function isValidRoutineBackupName(filename: string) {
|
||||
export function isValidDatabaseRoutineBackupName(filename: string) {
|
||||
const oldBackupStyle = filename.match(/^immich-db-backup-\d+\.sql\.gz$/);
|
||||
//immich-db-backup-20250729T114018-v1.136.0-pg14.17.sql.gz
|
||||
const newBackupStyle = filename.match(/^immich-db-backup-\d{8}T\d{6}-v.*-pg.*\.sql\.gz$/);
|
||||
return oldBackupStyle || newBackupStyle;
|
||||
}
|
||||
|
||||
export function isFailedBackupName(filename: string) {
|
||||
export function isFailedDatabaseBackupName(filename: string) {
|
||||
return filename.match(/^immich-db-backup-.*\.sql\.gz\.tmp$/);
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ export async function buildPostgresLaunchArguments(
|
||||
};
|
||||
}
|
||||
|
||||
export async function createBackup(
|
||||
export async function createDatabaseBackup(
|
||||
{ logger, storage, process: processRepository, ...pgRepos }: BackupRepos,
|
||||
filenamePrefix: string = '',
|
||||
): Promise<void> {
|
||||
@@ -179,7 +179,7 @@ export async function createBackup(
|
||||
logger.log(`Database Backup Success`);
|
||||
}
|
||||
|
||||
export async function restoreBackup(
|
||||
export async function restoreDatabaseBackup(
|
||||
{ logger, storage, process: processRepository, ...pgRepos }: BackupRepos,
|
||||
filename: string,
|
||||
progressCb?: (action: 'backup' | 'restore', progress: number) => void,
|
||||
@@ -188,7 +188,7 @@ export async function restoreBackup(
|
||||
|
||||
let complete = false;
|
||||
try {
|
||||
if (!isValidBackupName(filename)) {
|
||||
if (!isValidDatabaseBackupName(filename)) {
|
||||
throw new Error('Invalid backup file format!');
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ export async function restoreBackup(
|
||||
|
||||
progressCb?.('backup', 0.05);
|
||||
|
||||
await createBackup({ logger, storage, process: processRepository, ...pgRepos }, 'restore-point-');
|
||||
await createDatabaseBackup({ logger, storage, process: processRepository, ...pgRepos }, 'restore-point-');
|
||||
|
||||
logger.log(`Database Restore Starting. Database Version: ${databaseMajorVersion}`);
|
||||
|
||||
@@ -266,32 +266,32 @@ export async function restoreBackup(
|
||||
logger.log(`Database Restore Success`);
|
||||
}
|
||||
|
||||
export async function deleteBackups({ storage }: Pick<BackupRepos, 'storage'>, files: string[]): Promise<void> {
|
||||
export async function deleteDatabaseBackup({ storage }: Pick<BackupRepos, 'storage'>, files: string[]): Promise<void> {
|
||||
const backupsFolder = StorageCore.getBaseFolder(StorageFolder.Backups);
|
||||
|
||||
if (files.some((filename) => !isValidBackupName(filename))) {
|
||||
if (files.some((filename) => !isValidDatabaseBackupName(filename))) {
|
||||
throw new BadRequestException('Invalid backup name!');
|
||||
}
|
||||
|
||||
await Promise.all(files.map((filename) => storage.unlink(path.join(backupsFolder, filename))));
|
||||
}
|
||||
|
||||
export async function listBackups({ storage }: Pick<BackupRepos, 'storage'>): Promise<string[]> {
|
||||
export async function listDatabaseBackups({ storage }: Pick<BackupRepos, 'storage'>): Promise<string[]> {
|
||||
const backupsFolder = StorageCore.getBaseFolder(StorageFolder.Backups);
|
||||
const files = await storage.readdir(backupsFolder);
|
||||
return files
|
||||
.filter((fn) => isValidBackupName(fn))
|
||||
.filter((fn) => isValidDatabaseBackupName(fn))
|
||||
.toSorted((a, b) => (a.startsWith('uploaded-') === b.startsWith('uploaded-') ? a.localeCompare(b) : 1))
|
||||
.toReversed();
|
||||
}
|
||||
|
||||
export async function uploadBackup(
|
||||
export async function uploadDatabaseBackup(
|
||||
{ storage }: Pick<BackupRepos, 'storage'>,
|
||||
file: Express.Multer.File,
|
||||
): Promise<void> {
|
||||
const backupsFolder = StorageCore.getBaseFolder(StorageFolder.Backups);
|
||||
const fn = basename(file.originalname);
|
||||
if (!isValidBackupName(fn)) {
|
||||
if (!isValidDatabaseBackupName(fn)) {
|
||||
throw new BadRequestException('Invalid backup name!');
|
||||
}
|
||||
|
||||
@@ -299,8 +299,8 @@ export async function uploadBackup(
|
||||
await storage.createOrOverwriteFile(path, file.buffer);
|
||||
}
|
||||
|
||||
export function downloadBackup(fileName: string) {
|
||||
if (!isValidBackupName(fileName)) {
|
||||
export function downloadDatabaseBackup(fileName: string) {
|
||||
if (!isValidDatabaseBackupName(fileName)) {
|
||||
throw new BadRequestException('Invalid backup name!');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user