Fix foreign key constraints and improve snapshot tracking
- Add unified compression/encryption package in internal/blobgen - Update DATAMODEL.md to reflect current schema implementation - Refactor snapshot cleanup into well-named methods for clarity - Add snapshot_id to uploads table to track new blobs per snapshot - Fix blob count reporting for incremental backups - Add DeleteOrphaned method to BlobChunkRepository - Fix cleanup order to respect foreign key constraints - Update tests to reflect schema changes
This commit is contained in:
73
internal/blobgen/reader.go
Normal file
73
internal/blobgen/reader.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package blobgen
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
|
||||
"filippo.io/age"
|
||||
"github.com/klauspost/compress/zstd"
|
||||
)
|
||||
|
||||
// Reader wraps decompression and decryption with SHA256 verification
|
||||
type Reader struct {
|
||||
reader io.Reader
|
||||
decompressor *zstd.Decoder
|
||||
decryptor io.Reader
|
||||
hasher hash.Hash
|
||||
teeReader io.Reader
|
||||
bytesRead int64
|
||||
}
|
||||
|
||||
// NewReader creates a new Reader that decrypts, decompresses, and verifies data
|
||||
func NewReader(r io.Reader, identity age.Identity) (*Reader, error) {
|
||||
// Create decryption reader
|
||||
decReader, err := age.Decrypt(r, identity)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating decryption reader: %w", err)
|
||||
}
|
||||
|
||||
// Create decompression reader
|
||||
decompressor, err := zstd.NewReader(decReader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating decompression reader: %w", err)
|
||||
}
|
||||
|
||||
// Create SHA256 hasher
|
||||
hasher := sha256.New()
|
||||
|
||||
// Create tee reader that reads from decompressor and writes to hasher
|
||||
teeReader := io.TeeReader(decompressor, hasher)
|
||||
|
||||
return &Reader{
|
||||
reader: r,
|
||||
decompressor: decompressor,
|
||||
decryptor: decReader,
|
||||
hasher: hasher,
|
||||
teeReader: teeReader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Read implements io.Reader
|
||||
func (r *Reader) Read(p []byte) (n int, err error) {
|
||||
n, err = r.teeReader.Read(p)
|
||||
r.bytesRead += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Close closes the decompressor
|
||||
func (r *Reader) Close() error {
|
||||
r.decompressor.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sum256 returns the SHA256 hash of all data read
|
||||
func (r *Reader) Sum256() []byte {
|
||||
return r.hasher.Sum(nil)
|
||||
}
|
||||
|
||||
// BytesRead returns the number of uncompressed bytes read
|
||||
func (r *Reader) BytesRead() int64 {
|
||||
return r.bytesRead
|
||||
}
|
||||
Reference in New Issue
Block a user