Skip to content

Commit

Permalink
feat(backup): backup save and upload service
Browse files Browse the repository at this point in the history
  • Loading branch information
wibus-wee committed Jul 18, 2022
1 parent a23cd9e commit 4595098
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
"handlebars": "^4.7.7",
"i": "^0.3.7",
"lodash": "*",
"mkdirp": "^1.0.4",
"mongoose": "6.4.4",
"mongoose-aggregate-paginate-v2": "1.0.6",
"mongoose-lean-id": "0.3.0",
Expand Down
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { ScheduleModule } from "@nestjs/schedule";
import { InitModule } from "./modules/init/init.module";
import { RolesGuard } from "./common/guard/roles.guard";
import { AuthModule } from "./modules/auth/auth.module";
import { BackupModule } from './modules/backup/backup.module';

@Module({
imports: [
Expand All @@ -43,6 +44,7 @@ import { AuthModule } from "./modules/auth/auth.module";
AggregateModule,
LinksModule,
InitModule,
BackupModule,
],
controllers: [AppController],
providers: [
Expand Down
1 change: 1 addition & 0 deletions src/constants/path.constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export const DATA_DIR = isDev
: join(HOME, `.${appName}`);
export const PLUGIN_DIR = join(DATA_DIR, "plugins");
export const LOG_DIR = join(DATA_DIR, "log");
export const BACKUP_DIR = join(DATA_DIR, "backup")
4 changes: 4 additions & 0 deletions src/modules/backup/backup.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Controller } from '@nestjs/common';

@Controller('backup')
export class BackupController {}
10 changes: 10 additions & 0 deletions src/modules/backup/backup.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { BackupService } from './backup.service';
import { BackupController } from './backup.controller';

@Module({
providers: [BackupService],
controllers: [BackupController],
exports: [BackupService],
})
export class BackupModule {}
85 changes: 85 additions & 0 deletions src/modules/backup/backup.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { BadRequestException, Injectable, Logger } from '@nestjs/common';
import { join } from 'path';
import { MONGO_DB } from '~/app.config';
import { BACKUP_DIR } from '~/constants/path.constant';
import { CacheService } from '~/processors/cache/cache.service';
import { getMediumDateTime } from '~/utils/time.util';
import { ConfigsService } from '../configs/configs.service';
import mkdirp from 'mkdirp';
import { quiet } from 'zx';
import { readFile, writeFile } from 'fs/promises';
import { existsSync } from 'fs';
@Injectable()
export class BackupService {
private logger: Logger

constructor(
private readonly configs: ConfigsService,
private readonly redis: CacheService,
) { }

async backup() {
this.logger.log('正在备份数据库...')
const dir = getMediumDateTime(new Date())
const backupPath = join(BACKUP_DIR, dir)
mkdirp.sync(backupPath)

try {
await $`mongodump -h ${MONGO_DB.host} --port ${MONGO_DB.port} -d ${MONGO_DB.dbName} -o ${backupPath} >/dev/null 2>&1` // 备份数据库
cd(backupPath) // 进入备份目录
await nothrow(quiet($`mv ${MONGO_DB.dbName} nx-space`)) // 移动备份文件
await quiet($`tar -czf nx-space-backup-${dir}.tar.gz nx-space/* && rm -rf nx-space`) // 压缩备份文件,并删除备份目录
this.logger.log('备份数据库完成')
} catch (e) {
this.logger.error(`备份数据库失败,请检查是否安装 mongo-tools, mongo-tools 的版本需要与 mongod 版本一致, ${e.message}` || e.stderr,)
throw e // 抛出异常
}
const path = join(backupPath, `nx-space-backup-${dir}.tar.gz`)
return {
buffer: await readFile(path), // 读取备份文件
path,
}
}

checkBackupExist(dirname: string) {
const path = join(BACKUP_DIR, dirname, `nx-space-backup-${dirname}.zip`)
if (!existsSync(path)) {
throw new BadRequestException('文件不存在')
}
return path
}

async getFileStream(dirname: string) {
const path = this.checkBackupExist(dirname)
const stream = fs.createReadStream(path)

return stream
}

async restore(buffer: Buffer) {
// 检查buffer是否为tar.gz文件
if (!buffer.slice(0, 2).toString('hex').includes('1f8b')) {
throw new Error('不是tar.gz文件')
}
// 检查大小
if (!buffer.length) {
throw new Error('文件为空')
}
this.logger.log('正在还原数据库...')
const dir = getMediumDateTime(new Date())
const backupPath = join(BACKUP_DIR, dir)
mkdirp.sync(backupPath)
const path = join(backupPath, `nx-space-backup-${dir}.tar.gz`)
try {
await writeFile(path, buffer) // 写入备份文件
cd(backupPath) // 进入备份目录
await nothrow(quiet($`tar -xzf nx-space-backup-${dir}.tar.gz`)) // 解压备份文件
await nothrow(quiet($`mongorestore -h ${MONGO_DB.host} --port ${MONGO_DB.port} -d ${MONGO_DB.dbName} ./nx-space --drop >/dev/null 2>&1`)) // 还原数据库
this.logger.log('还原数据库完成')
} catch (e) {
this.logger.error(`还原数据库失败,请检查是否安装 mongo-tools, mongo-tools 的版本需要与 mongod 版本一致, ${e.message}` || e.stderr,)
throw e // 抛出异常
}
}

}
18 changes: 18 additions & 0 deletions test/src/modules/backup/backup.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { BackupController } from '~/modules/backup/backup.controller';
import { beforeEach, describe, expect, it } from "vitest";
describe('BackupController', () => {
let controller: BackupController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [BackupController],
}).compile();

controller = module.get<BackupController>(BackupController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
18 changes: 18 additions & 0 deletions test/src/modules/backup/backup.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { BackupService } from '~/modules/backup/backup.service';
import { beforeEach, describe, expect, it } from "vitest";
describe('BackupService', () => {
let service: BackupService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [BackupService],
}).compile();

service = module.get<BackupService>(BackupService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});

0 comments on commit 4595098

Please sign in to comment.