// Code scaffolded by goctl. Safe to edit. // goctl 1.10.2 package systemlog import ( "archive/zip" "context" "fmt" "io" "net/http" "os" "path/filepath" "udeServer/internal/apierr" "udeServer/internal/log" "udeServer/internal/svc" "udeServer/internal/types" "github.com/zeromicro/go-zero/core/logx" ) type LogArchiveDownloadLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } // 归档打包下载(zip) func NewLogArchiveDownloadLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LogArchiveDownloadLogic { return &LogArchiveDownloadLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } // LogArchiveDownload streams the selected archive files back as one zip. // The response is written to w directly (no unified envelope); the handler // therefore must not call httpx.OkJsonCtx afterwards. func (l *LogArchiveDownloadLogic) LogArchiveDownload(w http.ResponseWriter, req *types.LogArchiveDownloadReq) error { if len(req.Ids) == 0 { return apierr.BadRequest("ids 不能为空") } if l.svcCtx.MinioClient == nil { return apierr.New(500, "MinIO客户端未加载,无法下载归档(检查t_config的file_*配置)") } log.RecordDebug(l.ctx, "开始下载Ids:%+v的归档!", req.Ids) list, err := l.svcCtx.LogArchiveRecordModel.FindByIds(l.ctx, req.Ids) if err != nil { log.RecordError(l.ctx, err) return apierr.New(500, "查询归档记录失败") } if len(list) == 0 { return apierr.New(404, "归档记录不存在") } w.Header().Set("Content-Type", "application/zip") w.Header().Set("Content-Disposition", "attachment; filename=archives.zip") zipWriter := zip.NewWriter(w) defer func() { _ = zipWriter.Close() }() for i := range list { v := &list[i] filePath, err := l.svcCtx.MinioClient.DownloadFile(l.ctx, v.ArchiveFileKey) if err != nil || filePath == "" { log.RecordError(l.ctx, fmt.Errorf("下载归档文件失败[ID:%d]: %v", v.Id, err)) return apierr.New(500, "下载归档文件失败") } if err := copyArchiveIntoZip(zipWriter, filePath, v.ArchiveFileKey); err != nil { log.RecordError(l.ctx, err) } } log.RecordDebug(l.ctx, "Ids:%+v的归档下载成功!", req.Ids) return nil } // copyArchiveIntoZip adds one archive file as a zip entry (temp file removed // afterwards). func copyArchiveIntoZip(zipWriter *zip.Writer, filePath, archiveFileKey string) error { // 1.删除临时文件 defer func() { _ = os.Remove(filePath) }() // 2.打开文件 file, err := os.Open(filePath) if err != nil { return fmt.Errorf("打开文件失败[%s]: %w", archiveFileKey, err) } defer func() { _ = file.Close() }() // 3.文件打包 zipFileName := filepath.Base(archiveFileKey) zipEntryWriter, err := zipWriter.Create(zipFileName) if err != nil { return fmt.Errorf("创建ZIP条目失败[%s]: %w", archiveFileKey, err) } if _, err := io.Copy(zipEntryWriter, file); err != nil { return fmt.Errorf("写入ZIP条目失败[%s]: %w", archiveFileKey, err) } return nil }