Skip to content

Commit

Permalink
add test for backup handler
Browse files Browse the repository at this point in the history
  • Loading branch information
xziy committed Jan 2, 2025
1 parent 081d656 commit 11f526f
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 206 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ dump.rdb
pnpm-*
coverage
.vscode/pinned-files.json
.tmp
162 changes: 83 additions & 79 deletions libs/BackupHandler.ts
Original file line number Diff line number Diff line change
@@ -1,157 +1,161 @@
import * as fs from 'fs';
import * as path from 'path';
import * as tar from 'tar';
import { GroupRecord } from '../models/Group';
import { DishRecord } from '../models/Dish';
import { MediaFileRecord } from '../models/MediaFile';
import { fsw } from './wrapper/fs';

interface BackupOptions {
isDeleted: boolean;
concepts: string[];
turncate: boolean
}

const defaultOptions: BackupOptions = {
isDeleted: false,
concepts: []
concepts: [],
turncate: false
};

export class BackupHandler {
private groups: GroupRecord[];
private dishes: DishRecord[];

constructor() {
}

// Method to export data to a tar file
private groups: GroupRecord[] = [];
private dishes: DishRecord[] = [];
tar = tar;
// Export data and images to a tar file
async exportToTar(filePath: string, options: Partial<BackupOptions> = {}): Promise<void> {
try {
const finalOptions = { ...defaultOptions, ...options };
const exportDir = path.dirname(filePath);

// Получаем текущую директорию для создания временной папки
const currentDir = process.cwd();

// Создаем временную директорию для экспорта
const timestamp = Date.now();
const exportDir = path.join(currentDir, `.tmp/backup-${timestamp}`);

// Создаем папку, если она не существует
await fsw.mkdir(exportDir);

// Путь для JSON файла
const jsonFilePath = path.join(exportDir, 'data.json');

// Create a JSON file with data
// Создание JSON данных
const jsonData = await this.createJSON(finalOptions);
fs.writeFileSync(jsonFilePath, jsonData);

// Export images
this.exportImages(this.dishes, exportDir);
await fsw.writeFile(jsonFilePath, jsonData);

// Pack into a tar file
await tar.c({
// Экспорт изображений в временную директорию
await this.exportImages(this.dishes, exportDir);

// Упаковка всего содержимого в tar файл
await this.tar.c({
gzip: true,
file: filePath,
cwd: exportDir
}, ['data.json']);

// Delete temporary files
fs.unlinkSync(jsonFilePath);
}, ['.']);

// Удаление временных файлов
await fsw.unlink(jsonFilePath);

console.log('Export completed:', filePath);
} catch (error) {
new Error
console.error('Export error:', error);
}
}

// Method to import data from a tar file
// Import data and images from a tar file
async importFromTar(filePath: string): Promise<void> {
try {
const extractDir = path.dirname(filePath);

// Extract the tar file
await tar.x({
// Получаем текущую директорию
const currentDir = process.cwd();

// Создаем директорию для распаковки
const timestamp = Date.now();
const extractDir = path.join(currentDir, `.tmp/backup-${timestamp}`);

// Создаем папку, если она не существует
await fsw.mkdir(extractDir);

console.log(`Extracting tar file to: ${extractDir}`);

// Распаковываем архив в указанную директорию
await this.tar.x({
file: filePath,
cwd: extractDir
cwd: extractDir,
});

// Read the JSON file
// Читаем данные JSON
const jsonFilePath = path.join(extractDir, 'data.json');
const jsonData = fs.readFileSync(jsonFilePath, 'utf-8');
const jsonData = await fsw.readFile(jsonFilePath);
const importedData = JSON.parse(jsonData);

this.groups = importedData.groups;
this.dishes = importedData.dishes;

// Check and load images
// Проверяем и загружаем изображения
for (const dish of this.dishes) {
if (dish.images && Array.isArray(dish.images)) {
for (const image of dish.images) {
const imagePath = path.join(extractDir, image.variant.origin);
this.checkAndLoadImage(imagePath);
const imagePath = path.join(extractDir, `${image.id}.jpg`);
this.checkAndLoadImage(imagePath); // Предположим, что это ваш метод для проверки и загрузки изображений
}
}
}

console.log('Import completed:', filePath);
} catch (error) {
console.error('Import error:', error);
}
}

// Internal method: Create JSON from structure
// Create JSON data
private async createJSON(options: BackupOptions): Promise<string> {
const groups = await Group.find({
isDeleted: options.isDeleted,
...options.concepts.length && { concepts: { contains: options.concepts } }
});
const dishes = await Dish.find({
isDeleted: options.isDeleted,
...options.concepts.length && { concepts: { contains: options.concepts } }
const groups = await Group.find({
isDeleted: options.isDeleted,
...(options.concepts.length && { concepts: { $in: options.concepts } })
});

const dishes = await Dish.find({
isDeleted: options.isDeleted,
...(options.concepts.length && { concepts: { $in: options.concepts } })
});

this.groups = groups;
this.dishes = dishes;

const kernelVersion = process.version;

return JSON.stringify({ kernelVersion, groups, dishes }, null, 2);
}

// Internal method: Load image
private loadImage(imagePath: string): void {
// Image loading implementation
console.log(`Loading image: ${imagePath}`);
}

// Internal method: Check for file existence and load image
private checkAndLoadImage(imagePath: string): void {
if (fs.existsSync(imagePath)) {
// Check file existence and load image
private async checkAndLoadImage(imagePath: string): Promise<void> {
if (await fsw.exists(imagePath)) {
this.loadImage(imagePath);
} else {
console.warn(`Image not found: ${imagePath}`);
}
}

// Simulate loading an image
private loadImage(imagePath: string): void {
console.log(`Loading image: ${imagePath}`);
}

// Method for exporting images
private exportImages(dishes: DishRecord[], exportDir: string): void {
console.log(`Exporting images to directory: ${exportDir}`);

// Create the directory for images if it doesn't exist
const imagesDir = path.join(exportDir, 'images');
if (!fs.existsSync(imagesDir)) {
fs.mkdirSync(imagesDir);
}
// Export images to a directory
private async exportImages(dishes: DishRecord[], exportDir: string): Promise<void> {
const imagesDir = path.join(exportDir);

// For each dish in dishes
dishes.forEach(dish => {
if (dish.images && Array.isArray(dish.images)) {
// For each image of the dish
dish.images.forEach((image: MediaFileRecord) => {
// Use 'variant' field for image paths
Object.entries(image.variant).forEach(([variantName, variantPath]) => {
Object.entries(image.variant).forEach(async ([variantName, variantPath]) => {
if (variantPath) {
const imageFileName = `${variantName}_${image.id}.jpg`; // Construct image name
const imageFileName = `${variantName}_${image.id}.jpg`;
const destinationPath = path.join(imagesDir, imageFileName);

// Check if the file exists
if (fs.existsSync(variantPath)) {
try {
// Copy the image to the export directory
fs.cpSync(variantPath, destinationPath);
console.log(`Image exported: ${imageFileName}`);
} catch (error) {
console.error(`Error exporting image ${imageFileName}:`, error);
}
if (await fsw.exists(variantPath)) {
await fsw.copyFile(variantPath, destinationPath);
console.log(`Image exported: ${imageFileName}`);
} else {
console.warn(`Image file not found: ${variantPath}`);
}
Expand All @@ -161,4 +165,4 @@ export class BackupHandler {
}
});
}
}
}
58 changes: 58 additions & 0 deletions libs/wrapper/fs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as fs from 'fs';
import * as path from 'path';

export const fsw = {
async writeFile(filePath: string, data: string): Promise<void> {
try {
await fs.promises.writeFile(filePath, data, 'utf-8');
} catch (error) {
console.error(`Error writing file ${filePath}:`, error);
throw error;
}
},

async readFile(filePath: string): Promise<string> {
try {
return await fs.promises.readFile(filePath, 'utf-8');
} catch (error) {
console.error(`Error reading file ${filePath}:`, error);
throw error;
}
},

async unlink(filePath: string): Promise<void> {
try {
await fs.promises.unlink(filePath);
} catch (error) {
console.error(`Error deleting file ${filePath}:`, error);
throw error;
}
},

async exists(filePath: string): Promise<boolean> {
try {
await fs.promises.access(filePath, fs.constants.F_OK);
return true;
} catch {
return false;
}
},

async mkdir(dirPath: string): Promise<void> {
try {
await fs.promises.mkdir(dirPath, { recursive: true });
} catch (error) {
console.error(`Error creating directory ${dirPath}:`, error);
throw error;
}
},

async copyFile(src: string, dest: string): Promise<void> {
try {
await fs.promises.copyFile(src, dest);
} catch (error) {
console.error(`Error copying file from ${src} to ${dest}:`, error);
throw error;
}
}
};
Loading

0 comments on commit 11f526f

Please sign in to comment.