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