1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-07-01 11:35:23 +00:00
v2fly/common/buf/copy.go

115 lines
2.7 KiB
Go
Raw Normal View History

2017-06-04 19:32:01 +00:00
package buf
import (
"io"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/signal"
)
type errorHandler func(error) error
type dataHandler func(MultiBuffer)
type copyHandler struct {
onReadError []errorHandler
onData []dataHandler
onWriteError []errorHandler
}
func (h *copyHandler) readFrom(reader Reader) (MultiBuffer, error) {
2017-11-09 21:33:15 +00:00
mb, err := reader.ReadMultiBuffer()
2017-06-04 19:32:01 +00:00
if err != nil {
for _, handler := range h.onReadError {
err = handler(err)
}
}
return mb, err
}
func (h *copyHandler) writeTo(writer Writer, mb MultiBuffer) error {
2017-11-09 21:33:15 +00:00
err := writer.WriteMultiBuffer(mb)
2017-06-04 19:32:01 +00:00
if err != nil {
for _, handler := range h.onWriteError {
err = handler(err)
}
}
return err
}
2018-02-13 10:15:04 +00:00
// SizeCounter is for counting bytes copied by Copy().
2017-11-09 21:33:15 +00:00
type SizeCounter struct {
Size int64
}
2017-11-21 16:02:55 +00:00
// CopyOption is an option for copying data.
2017-06-04 19:32:01 +00:00
type CopyOption func(*copyHandler)
2017-11-21 16:02:55 +00:00
// IgnoreReaderError is a CopyOption that ignores errors from reader. Copy will continue in such case.
2017-06-04 19:32:01 +00:00
func IgnoreReaderError() CopyOption {
return func(handler *copyHandler) {
handler.onReadError = append(handler.onReadError, func(err error) error {
return nil
})
}
}
2017-11-21 16:02:55 +00:00
// IgnoreWriterError is a CopyOption that ignores errors from writer. Copy will continue in such case.
2017-06-04 19:32:01 +00:00
func IgnoreWriterError() CopyOption {
return func(handler *copyHandler) {
handler.onWriteError = append(handler.onWriteError, func(err error) error {
return nil
})
}
}
2017-11-21 16:02:55 +00:00
// UpdateActivity is a CopyOption to update activity on each data copy operation.
func UpdateActivity(timer signal.ActivityUpdater) CopyOption {
2017-06-04 19:32:01 +00:00
return func(handler *copyHandler) {
handler.onData = append(handler.onData, func(MultiBuffer) {
timer.Update()
})
}
}
2017-11-21 16:02:55 +00:00
// CountSize is a CopyOption that sums the total size of data copied into the given SizeCounter.
2017-11-09 21:33:15 +00:00
func CountSize(sc *SizeCounter) CopyOption {
return func(handler *copyHandler) {
handler.onData = append(handler.onData, func(b MultiBuffer) {
sc.Size += int64(b.Len())
})
}
}
2017-06-04 19:32:01 +00:00
func copyInternal(reader Reader, writer Writer, handler *copyHandler) error {
for {
buffer, err := handler.readFrom(reader)
if !buffer.IsEmpty() {
for _, handler := range handler.onData {
handler(buffer)
}
if werr := handler.writeTo(writer, buffer); werr != nil {
buffer.Release()
return werr
}
2018-02-19 16:50:53 +00:00
}
if err != nil {
2017-06-04 19:32:01 +00:00
return err
}
}
}
2017-11-21 16:02:55 +00:00
// Copy dumps all payload from reader to writer or stops when an error occurs. It returns nil when EOF.
2017-06-04 19:32:01 +00:00
func Copy(reader Reader, writer Writer, options ...CopyOption) error {
handler := new(copyHandler)
for _, option := range options {
option(handler)
}
err := copyInternal(reader, writer, handler)
if err != nil && errors.Cause(err) != io.EOF {
return err
}
return nil
}