mirror of
https://github.com/TronoSfera/backupy-agent.git
synced 2026-05-18 18:13:30 +03:00
Source ports from the TronoSfera/backupy-cloud monorepo:
- apps/agent/ — Go agent (WSS client, persistent queue, Docker
discovery, 5 DB drivers: PG/MySQL/Mongo/Redis/SQLite,
pre/post hooks, Prometheus metrics)
- apps/backupy-decrypt/ — standalone CLI for client-side decryption
- packages/proto/ — protobuf wire format (generated .pb.go committed
so the repo builds without protoc)
- docs/ — agent spec + wire-protocol contract
Apache-2.0 license. Image published to ghcr.io/tronosfera/backupy-agent
on every v* tag via .github/workflows/release.yml (multi-arch amd64+arm64).
65 lines
2 KiB
Go
65 lines
2 KiB
Go
package pipeline
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/klauspost/compress/zstd"
|
|
)
|
|
|
|
// CompressZstd streams `in` through a zstd encoder into `out`.
|
|
//
|
|
// Returns:
|
|
// - originalBytes : plaintext bytes consumed from `in`
|
|
// - compressedBytes: zstd-framed bytes written to `out`
|
|
//
|
|
// The encoder is created with the default level (SpeedDefault, ~level 3) —
|
|
// a sensible balance between ratio and CPU for streaming DB dumps. Callers
|
|
// who need a different level should use the lower-level zstdWriter directly.
|
|
func CompressZstd(in io.Reader, out io.Writer) (int64, int64, error) {
|
|
cw := &countingWriter{w: out}
|
|
enc, err := zstd.NewWriter(cw, zstd.WithEncoderLevel(zstd.SpeedDefault))
|
|
if err != nil {
|
|
return 0, 0, fmt.Errorf("pipeline: zstd new writer: %w", err)
|
|
}
|
|
// NOTE: do NOT defer enc.Close() here. klauspost's zstd writer emits
|
|
// an additional empty frame on a second Close() — if we both defer and
|
|
// close explicitly, the trailing 4 bytes corrupt the downstream stream
|
|
// and skew `cw.n`. We close exactly once below and ensure the encoder
|
|
// is released on error paths too.
|
|
|
|
n, err := io.Copy(enc, in)
|
|
if err != nil {
|
|
_ = enc.Close()
|
|
return n, cw.n, fmt.Errorf("pipeline: zstd copy: %w", err)
|
|
}
|
|
if err := enc.Close(); err != nil {
|
|
return n, cw.n, fmt.Errorf("pipeline: zstd close: %w", err)
|
|
}
|
|
return n, cw.n, nil
|
|
}
|
|
|
|
// NewZstdWriter wraps `out` in a zstd encoder. Callers MUST Close the
|
|
// returned writer before the stream is considered final — the trailer
|
|
// would otherwise be missing.
|
|
func NewZstdWriter(out io.Writer) (io.WriteCloser, error) {
|
|
enc, err := zstd.NewWriter(out, zstd.WithEncoderLevel(zstd.SpeedDefault))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("pipeline: zstd new writer: %w", err)
|
|
}
|
|
return enc, nil
|
|
}
|
|
|
|
// countingWriter is an io.Writer that counts bytes written to the
|
|
// wrapped writer. Used to measure compressed output size without
|
|
// double-buffering.
|
|
type countingWriter struct {
|
|
w io.Writer
|
|
n int64
|
|
}
|
|
|
|
func (c *countingWriter) Write(p []byte) (int, error) {
|
|
n, err := c.w.Write(p)
|
|
c.n += int64(n)
|
|
return n, err
|
|
}
|