github.com/ethersphere/bee/v2@v2.2.0/pkg/file/buffer.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package file 6 7 import ( 8 "io" 9 10 "github.com/ethersphere/bee/v2/pkg/swarm" 11 ) 12 13 const ( 14 maxBufferSize = swarm.ChunkSize * 2 15 ) 16 17 // ChunkPipe ensures that only the last read is smaller than the chunk size, 18 // regardless of size of individual writes. 19 type ChunkPipe struct { 20 io.ReadCloser 21 writer io.WriteCloser 22 data []byte 23 cursor int 24 } 25 26 // Creates a new ChunkPipe 27 func NewChunkPipe() io.ReadWriteCloser { 28 r, w := io.Pipe() 29 return &ChunkPipe{ 30 ReadCloser: r, 31 writer: w, 32 data: make([]byte, maxBufferSize), 33 } 34 } 35 36 // Read implements io.Reader 37 func (c *ChunkPipe) Read(b []byte) (int, error) { 38 return c.ReadCloser.Read(b) 39 } 40 41 // Writer implements io.Writer 42 func (c *ChunkPipe) Write(b []byte) (int, error) { 43 nw := 0 44 45 for { 46 if nw >= len(b) { 47 break 48 } 49 50 copied := copy(c.data[c.cursor:], b[nw:]) 51 c.cursor += copied 52 nw += copied 53 54 if c.cursor >= swarm.ChunkSize { 55 // NOTE: the Write method contract requires all sent data to be 56 // written before returning (without error) 57 written, err := c.writer.Write(c.data[:swarm.ChunkSize]) 58 if err != nil { 59 return nw, err 60 } 61 if swarm.ChunkSize != written { 62 return nw, io.ErrShortWrite 63 } 64 65 c.cursor -= swarm.ChunkSize 66 67 copy(c.data, c.data[swarm.ChunkSize:]) 68 } 69 } 70 71 return nw, nil 72 } 73 74 // Close implements io.Closer 75 func (c *ChunkPipe) Close() error { 76 if c.cursor > 0 { 77 written, err := c.writer.Write(c.data[:c.cursor]) 78 if err != nil { 79 return err 80 } 81 if c.cursor != written { 82 return io.ErrShortWrite 83 } 84 } 85 return c.writer.Close() 86 }