package example import ( "context" "errors" "kra/internal/biz/example" "kra/internal/data/model" "gorm.io/gorm" ) type breakpointContinueRepo struct { db *gorm.DB } // NewBreakpointContinueRepo 创建断点续传仓储 func NewBreakpointContinueRepo(db *gorm.DB) example.BreakpointContinueRepo { return &breakpointContinueRepo{db: db} } // FindOrCreateFile 查找或创建文件记录 func (r *breakpointContinueRepo) FindOrCreateFile(ctx context.Context, fileMd5, fileName string, chunkTotal int) (*example.ExaFile, error) { var file model.ExaFile cfile := model.ExaFile{ FileMd5: fileMd5, FileName: fileName, ChunkTotal: int64(chunkTotal), } // 检查是否已有完成的文件 if errors.Is(r.db.WithContext(ctx).Where("file_md5 = ? AND is_finish = ?", fileMd5, true).First(&file).Error, gorm.ErrRecordNotFound) { // 没有完成的文件,查找或创建 err := r.db.WithContext(ctx).Where("file_md5 = ? AND file_name = ?", fileMd5, fileName). FirstOrCreate(&file, cfile).Error if err != nil { return nil, err } // 加载切片 var chunks []model.ExaFileChunk r.db.WithContext(ctx).Where("exa_file_id = ?", file.ID).Find(&chunks) return toBizExaFileWithChunks(&file, chunks), nil } // 已有完成的文件,创建新记录 cfile.IsFinish = true cfile.FilePath = file.FilePath if err := r.db.WithContext(ctx).Create(&cfile).Error; err != nil { return nil, err } return toBizExaFileWithChunks(&cfile, nil), nil } // CreateFileChunk 创建文件切片记录 func (r *breakpointContinueRepo) CreateFileChunk(ctx context.Context, fileID uint, fileChunkPath string, fileChunkNumber int) error { chunk := model.ExaFileChunk{ ExaFileID: int64(fileID), FileChunkPath: fileChunkPath, FileChunkNumber: int64(fileChunkNumber), } return r.db.WithContext(ctx).Create(&chunk).Error } // DeleteFileChunk 删除文件切片记录 func (r *breakpointContinueRepo) DeleteFileChunk(ctx context.Context, fileMd5, filePath string) error { var file model.ExaFile err := r.db.WithContext(ctx).Where("file_md5 = ?", fileMd5).First(&file). Updates(map[string]interface{}{ "is_finish": true, "file_path": filePath, }).Error if err != nil { return err } return r.db.WithContext(ctx).Where("exa_file_id = ?", file.ID).Delete(&model.ExaFileChunk{}).Unscoped().Error } // 转换函数 func toBizExaFileWithChunks(m *model.ExaFile, chunks []model.ExaFileChunk) *example.ExaFile { file := &example.ExaFile{ ID: uint(m.ID), FileName: m.FileName, FileMd5: m.FileMd5, FilePath: m.FilePath, ChunkTotal: int(m.ChunkTotal), IsFinish: m.IsFinish, } if len(chunks) > 0 { file.ExaFileChunk = make([]example.ExaFileChunk, len(chunks)) for i, chunk := range chunks { file.ExaFileChunk[i] = example.ExaFileChunk{ ID: uint(chunk.ID), ExaFileID: uint(chunk.ExaFileID), FileChunkNumber: int(chunk.FileChunkNumber), FileChunkPath: chunk.FileChunkPath, } } } return file }