diff options
| author | pablu <me@pablu.de> | 2026-08-05 13:06:36 +0200 |
|---|---|---|
| committer | pablu <me@pablu.de> | 2026-08-05 16:11:59 +0200 |
| commit | aa9d403d09186b5b0cc9da3b322c1ba53c0f832a (patch) | |
| tree | 02ce07ae0a15e01f3f03bb469ccc2cb9fede56cc /download.go | |
| parent | 67916c5d1c7001bab5bf08b6fec3a7f14ea4dd64 (diff) | |
feat: create working client
Diffstat (limited to 'download.go')
| -rw-r--r-- | download.go | 71 |
1 files changed, 71 insertions, 0 deletions
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 +} |
