feat: Support for asynchronously obtaining the backup file size (#7660)

This commit is contained in:
ssongliu 2025-01-07 14:35:33 +08:00 committed by GitHub
parent 95ec6c62ef
commit 83db40e261
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 186 additions and 28 deletions

View file

@ -162,6 +162,29 @@ func (b *BaseApi) SearchBackupRecords(c *gin.Context) {
})
}
// @Tags Backup Account
// @Summary Load backup records size
// @Accept json
// @Param request body dto.RecordSearch true "request"
// @Success 200 {array} dto.dto.BackupFile
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /settings/backup/record/size [post]
func (b *BaseApi) LoadBackupSize(c *gin.Context) {
var req dto.RecordSearch
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
list, err := backupService.LoadSize(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, list)
}
// @Tags Backup Account
// @Summary Page backup records by cronjob
// @Accept json
@ -188,6 +211,29 @@ func (b *BaseApi) SearchBackupRecordsByCronjob(c *gin.Context) {
})
}
// @Tags Backup Account
// @Summary Load backup records size for cronjob
// @Accept json
// @Param request body dto.RecordSearchByCronjob true "request"
// @Success 200 {array} dto.dto.BackupFile
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /settings/backup/record/size/bycronjob [post]
func (b *BaseApi) LoadBackupSizeByCronjob(c *gin.Context) {
var req dto.RecordSearchByCronjob
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
list, err := backupService.LoadSizeByCronjob(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, list)
}
// @Tags Backup Account
// @Summary Download backup record
// @Accept json

View file

@ -21,6 +21,12 @@ type BackupInfo struct {
Vars string `json:"vars"`
}
type BackupFile struct {
ID uint `json:"id"`
Name string `json:"name"`
Size int64 `json:"size"`
}
type OneDriveInfo struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
@ -66,7 +72,6 @@ type BackupRecords struct {
BackupType string `json:"backupType"`
FileDir string `json:"fileDir"`
FileName string `json:"fileName"`
Size int64 `json:"size"`
}
type DownloadRecord struct {

View file

@ -8,7 +8,6 @@ import (
"fmt"
"os"
"path"
"sort"
"strings"
"sync"
"time"
@ -30,7 +29,9 @@ type BackupService struct{}
type IBackupService interface {
List() ([]dto.BackupInfo, error)
SearchRecordsWithPage(search dto.RecordSearch) (int64, []dto.BackupRecords, error)
LoadSize(req dto.RecordSearch) ([]dto.BackupFile, error)
SearchRecordsByCronjobWithPage(search dto.RecordSearchByCronjob) (int64, []dto.BackupRecords, error)
LoadSizeByCronjob(req dto.RecordSearchByCronjob) ([]dto.BackupFile, error)
LoadOneDriveInfo() (dto.OneDriveInfo, error)
DownloadRecord(info dto.DownloadRecord) (string, error)
Create(backupDto dto.BackupOperate) error
@ -94,11 +95,29 @@ func (u *BackupService) SearchRecordsWithPage(search dto.RecordSearch) (int64, [
return 0, nil, err
}
datas, err := u.loadRecordSize(records)
sort.Slice(datas, func(i, j int) bool {
return datas[i].CreatedAt.After(datas[j].CreatedAt)
})
return total, datas, err
var list []dto.BackupRecords
for _, item := range records {
var itemRecord dto.BackupRecords
if err := copier.Copy(&itemRecord, &item); err != nil {
continue
}
list = append(list, itemRecord)
}
return total, list, err
}
func (u *BackupService) LoadSize(req dto.RecordSearch) ([]dto.BackupFile, error) {
_, records, err := backupRepo.PageRecord(
req.Page, req.PageSize,
commonRepo.WithOrderBy("created_at desc"),
commonRepo.WithByName(req.Name),
commonRepo.WithByType(req.Type),
backupRepo.WithByDetailName(req.DetailName),
)
if err != nil {
return nil, err
}
return u.loadRecordSize(records)
}
func (u *BackupService) ListAppRecords(name, detailName, fileName string) ([]model.BackupRecord, error) {
@ -125,11 +144,27 @@ func (u *BackupService) SearchRecordsByCronjobWithPage(search dto.RecordSearchBy
return 0, nil, err
}
datas, err := u.loadRecordSize(records)
sort.Slice(datas, func(i, j int) bool {
return datas[i].CreatedAt.After(datas[j].CreatedAt)
})
return total, datas, err
var list []dto.BackupRecords
for _, item := range records {
var itemRecord dto.BackupRecords
if err := copier.Copy(&itemRecord, &item); err != nil {
continue
}
list = append(list, itemRecord)
}
return total, list, err
}
func (u *BackupService) LoadSizeByCronjob(req dto.RecordSearchByCronjob) ([]dto.BackupFile, error) {
_, records, err := backupRepo.PageRecord(
req.Page, req.PageSize,
commonRepo.WithOrderBy("created_at desc"),
backupRepo.WithByCronID(req.CronjobID),
)
if err != nil {
return nil, err
}
return u.loadRecordSize(records)
}
type loadSizeHelper struct {
@ -482,15 +517,14 @@ func (u *BackupService) loadAccessToken(backup *model.BackupAccount) error {
return nil
}
func (u *BackupService) loadRecordSize(records []model.BackupRecord) ([]dto.BackupRecords, error) {
var datas []dto.BackupRecords
func (u *BackupService) loadRecordSize(records []model.BackupRecord) ([]dto.BackupFile, error) {
var datas []dto.BackupFile
clientMap := make(map[string]loadSizeHelper)
var wg sync.WaitGroup
for i := 0; i < len(records); i++ {
var item dto.BackupRecords
if err := copier.Copy(&item, &records[i]); err != nil {
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
var item dto.BackupFile
item.ID = records[i].ID
item.Name = records[i].FileName
itemPath := path.Join(records[i].FileDir, records[i].FileName)
if _, ok := clientMap[records[i].Source]; !ok {
backup, err := backupRepo.Get(commonRepo.WithByType(records[i].Source))

View file

@ -56,7 +56,9 @@ func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) {
settingRouter.POST("/backup/del", baseApi.DeleteBackup)
settingRouter.POST("/backup/update", baseApi.UpdateBackup)
settingRouter.POST("/backup/record/search", baseApi.SearchBackupRecords)
settingRouter.POST("/backup/record/size", baseApi.LoadBackupSize)
settingRouter.POST("/backup/record/search/bycronjob", baseApi.SearchBackupRecordsByCronjob)
settingRouter.POST("/backup/record/size/bycronjob", baseApi.LoadBackupSizeByCronjob)
settingRouter.POST("/backup/record/download", baseApi.DownloadRecord)
settingRouter.POST("/backup/record/del", baseApi.DeleteBackupRecord)

View file

@ -40,6 +40,11 @@ export namespace Backup {
fileDir: string;
fileName: string;
}
export interface BackupFile {
id: number;
name: string;
size: number;
}
export interface ForBucket {
type: string;
accessKey: string;

View file

@ -124,9 +124,15 @@ export const deleteBackupRecord = (params: { ids: number[] }) => {
export const searchBackupRecords = (params: Backup.SearchBackupRecord) => {
return http.post<ResPage<Backup.RecordInfo>>(`/settings/backup/record/search`, params, TimeoutEnum.T_5M);
};
export const loadBackupSize = (param: Backup.SearchBackupRecord) => {
return http.post<Array<Backup.BackupFile>>(`/settings/backup/record/size`, param);
};
export const searchBackupRecordsByCronjob = (params: Backup.SearchBackupRecordByCronjob) => {
return http.post<ResPage<Backup.RecordInfo>>(`/settings/backup/record/search/bycronjob`, params, TimeoutEnum.T_5M);
};
export const loadCronjobBackupSize = (param: Backup.SearchBackupRecordByCronjob) => {
return http.post<Array<Backup.BackupFile>>(`/settings/backup/record/size/bycronjob`, param);
};
export const getBackupList = () => {
return http.get<Array<Backup.BackupInfo>>(`/settings/backup/search`);

View file

@ -48,10 +48,15 @@
<el-table-column :label="$t('commons.table.name')" prop="fileName" show-overflow-tooltip />
<el-table-column :label="$t('file.size')" prop="size" show-overflow-tooltip>
<template #default="{ row }">
<div v-if="row.hasLoad">
<span v-if="row.size">
{{ computeSize(row.size) }}
</span>
<span v-else>-</span>
</div>
<div v-if="!row.hasLoad">
<el-button link loading></el-button>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('database.source')" prop="backupType">
@ -110,7 +115,7 @@ import { computeSize, dateFormat, downloadFile } from '@/utils/util';
import { getBackupList, handleBackup, handleRecover } from '@/api/modules/setting';
import i18n from '@/lang';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { deleteBackupRecord, downloadBackupRecord, searchBackupRecords } from '@/api/modules/setting';
import { deleteBackupRecord, downloadBackupRecord, searchBackupRecords, loadBackupSize } from '@/api/modules/setting';
import { Backup } from '@/api/interface/backup';
import router from '@/routers';
import { MsgSuccess } from '@/utils/message';
@ -197,6 +202,31 @@ const search = async () => {
loading.value = false;
data.value = res.data.items || [];
paginationConfig.total = res.data.total;
if (paginationConfig.total !== 0) {
loadSize(params);
}
})
.catch(() => {
loading.value = false;
});
};
const loadSize = async (params: any) => {
await loadBackupSize(params)
.then((res) => {
let stats = res.data || [];
if (stats.length === 0) {
return;
}
for (const backup of data.value) {
for (const item of stats) {
if (backup.id === item.id) {
backup.hasLoad = true;
backup.size = item.size;
break;
}
}
}
})
.catch(() => {
loading.value = false;

View file

@ -26,10 +26,15 @@
<el-table-column :label="$t('commons.table.name')" prop="fileName" show-overflow-tooltip />
<el-table-column :label="$t('file.size')" prop="size" show-overflow-tooltip>
<template #default="{ row }">
<div v-if="row.hasLoad">
<span v-if="row.size">
{{ computeSize(row.size) }}
</span>
<span v-else>-</span>
</div>
<div v-if="!row.hasLoad">
<el-button link loading></el-button>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('database.source')" prop="backupType">
@ -57,7 +62,7 @@ import { reactive, ref } from 'vue';
import { computeSize, dateFormat, downloadFile } from '@/utils/util';
import i18n from '@/lang';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { downloadBackupRecord, searchBackupRecordsByCronjob } from '@/api/modules/setting';
import { downloadBackupRecord, loadCronjobBackupSize, searchBackupRecordsByCronjob } from '@/api/modules/setting';
import { Backup } from '@/api/interface/backup';
const selects = ref<any>([]);
@ -101,6 +106,31 @@ const search = async () => {
loading.value = false;
data.value = res.data.items || [];
paginationConfig.total = res.data.total;
if (paginationConfig.total !== 0) {
loadSize(params);
}
})
.catch(() => {
loading.value = false;
});
};
const loadSize = async (params: any) => {
await loadCronjobBackupSize(params)
.then((res) => {
let stats = res.data || [];
if (stats.length === 0) {
return;
}
for (const backup of data.value) {
for (const item of stats) {
if (backup.id === item.id) {
backup.hasLoad = true;
backup.size = item.size;
break;
}
}
}
})
.catch(() => {
loading.value = false;