From aa9d403d09186b5b0cc9da3b322c1ba53c0f832a Mon Sep 17 00:00:00 2001 From: pablu Date: Wed, 5 Aug 2026 13:06:36 +0200 Subject: feat: create working client --- download.go | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 download.go (limited to 'download.go') diff --git a/download.go b/download.go new file mode 100644 index 0000000..19dd1b2 --- /dev/null +++ b/download.go @@ -0,0 +1,71 @@ +package zw + +import ( + "context" + "io" + "io/fs" + "sync" + "sync/atomic" +) + +type downloadReader struct { + recv func() ([]byte, error) + cancel context.CancelFunc + + pending []byte + terminal error + + cancelOnce sync.Once + closed atomic.Bool +} + +func (r *downloadReader) Read(destination []byte) (int, error) { + if len(destination) == 0 { + return 0, nil + } + + if r.closed.Load() { + return 0, fs.ErrClosed + } + + if len(r.pending) > 0 { + n := copy(destination, r.pending) + r.pending = r.pending[n:] + return n, nil + } + + if r.terminal != nil { + return 0, r.terminal + } + + for { + chunk, err := r.recv() + if err != nil { + if r.closed.Load() { + return 0, fs.ErrClosed + } + + if err == io.EOF { + r.terminal = io.EOF + } else { + r.terminal = convertRPCError(err) + } + r.cancelOnce.Do(r.cancel) + return 0, r.terminal + } + + if len(chunk) == 0 { + continue + } + + n := copy(destination, chunk) + r.pending = chunk[n:] + return n, nil + } +} + +func (r *downloadReader) Close() error { + r.closed.Store(true) + r.cancelOnce.Do(r.cancel) + return nil +} -- cgit 1.3.1