Hunter0x7c7
2022-08-11 a82f9cb69f63aaeba40c024960deda7d75b9fece
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package buf
 
import (
    "io"
    "time"
 
    "github.com/v2fly/v2ray-core/v5/common/errors"
    "github.com/v2fly/v2ray-core/v5/common/signal"
)
 
type dataHandler func(MultiBuffer)
 
type copyHandler struct {
    onData []dataHandler
}
 
// SizeCounter is for counting bytes copied by Copy().
type SizeCounter struct {
    Size int64
}
 
// CopyOption is an option for copying data.
type CopyOption func(*copyHandler)
 
// UpdateActivity is a CopyOption to update activity on each data copy operation.
func UpdateActivity(timer signal.ActivityUpdater) CopyOption {
    return func(handler *copyHandler) {
        handler.onData = append(handler.onData, func(MultiBuffer) {
            timer.Update()
        })
    }
}
 
// CountSize is a CopyOption that sums the total size of data copied into the given SizeCounter.
func CountSize(sc *SizeCounter) CopyOption {
    return func(handler *copyHandler) {
        handler.onData = append(handler.onData, func(b MultiBuffer) {
            sc.Size += int64(b.Len())
        })
    }
}
 
type readError struct {
    error
}
 
func (e readError) Error() string {
    return e.error.Error()
}
 
func (e readError) Inner() error {
    return e.error
}
 
// IsReadError returns true if the error in Copy() comes from reading.
func IsReadError(err error) bool {
    _, ok := err.(readError)
    return ok
}
 
type writeError struct {
    error
}
 
func (e writeError) Error() string {
    return e.error.Error()
}
 
func (e writeError) Inner() error {
    return e.error
}
 
// IsWriteError returns true if the error in Copy() comes from writing.
func IsWriteError(err error) bool {
    _, ok := err.(writeError)
    return ok
}
 
func copyInternal(reader Reader, writer Writer, handler *copyHandler) error {
    for {
        buffer, err := reader.ReadMultiBuffer()
        if !buffer.IsEmpty() {
            for _, handler := range handler.onData {
                handler(buffer)
            }
 
            if werr := writer.WriteMultiBuffer(buffer); werr != nil {
                return writeError{werr}
            }
        }
 
        if err != nil {
            return readError{err}
        }
    }
}
 
// Copy dumps all payload from reader to writer or stops when an error occurs. It returns nil when EOF.
func Copy(reader Reader, writer Writer, options ...CopyOption) error {
    var handler copyHandler
    for _, option := range options {
        option(&handler)
    }
    err := copyInternal(reader, writer, &handler)
    if err != nil && errors.Cause(err) != io.EOF {
        return err
    }
    return nil
}
 
var ErrNotTimeoutReader = newError("not a TimeoutReader")
 
func CopyOnceTimeout(reader Reader, writer Writer, timeout time.Duration) error {
    timeoutReader, ok := reader.(TimeoutReader)
    if !ok {
        return ErrNotTimeoutReader
    }
    mb, err := timeoutReader.ReadMultiBufferTimeout(timeout)
    if err != nil {
        return err
    }
    return writer.WriteMultiBuffer(mb)
}