1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-11-17 18:06:15 -05:00
v2fly/common/buf/copy.go

129 lines
3.0 KiB
Go
Raw Normal View History

2017-06-04 15:32:01 -04:00
package buf
import (
"io"
"time"
2017-06-04 15:32:01 -04:00
"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 16:33:15 -05:00
mb, err := reader.ReadMultiBuffer()
2017-06-04 15:32:01 -04: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 16:33:15 -05:00
err := writer.WriteMultiBuffer(mb)
2017-06-04 15:32:01 -04:00
if err != nil {
for _, handler := range h.onWriteError {
err = handler(err)
}
}
return err
}
2018-02-13 05:15:04 -05:00
// SizeCounter is for counting bytes copied by Copy().
2017-11-09 16:33:15 -05:00
type SizeCounter struct {
Size int64
}
2017-11-21 11:02:55 -05:00
// CopyOption is an option for copying data.
2017-06-04 15:32:01 -04:00
type CopyOption func(*copyHandler)
2017-11-21 11:02:55 -05:00
// IgnoreReaderError is a CopyOption that ignores errors from reader. Copy will continue in such case.
2017-06-04 15:32:01 -04:00
func IgnoreReaderError() CopyOption {
return func(handler *copyHandler) {
handler.onReadError = append(handler.onReadError, func(err error) error {
return nil
})
}
}
2017-11-21 11:02:55 -05:00
// IgnoreWriterError is a CopyOption that ignores errors from writer. Copy will continue in such case.
2017-06-04 15:32:01 -04:00
func IgnoreWriterError() CopyOption {
return func(handler *copyHandler) {
handler.onWriteError = append(handler.onWriteError, func(err error) error {
return nil
})
}
}
2017-11-21 11:02:55 -05:00
// UpdateActivity is a CopyOption to update activity on each data copy operation.
func UpdateActivity(timer signal.ActivityUpdater) CopyOption {
2017-06-04 15:32:01 -04:00
return func(handler *copyHandler) {
handler.onData = append(handler.onData, func(MultiBuffer) {
timer.Update()
})
}
}
2017-11-21 11:02:55 -05:00
// CountSize is a CopyOption that sums the total size of data copied into the given SizeCounter.
2017-11-09 16:33:15 -05: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 15:32:01 -04: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 {
return werr
}
2018-02-19 11:50:53 -05:00
}
if err != nil {
2017-06-04 15:32:01 -04:00
return err
}
}
}
2017-11-21 11:02:55 -05:00
// Copy dumps all payload from reader to writer or stops when an error occurs. It returns nil when EOF.
2017-06-04 15:32:01 -04:00
func Copy(reader Reader, writer Writer, options ...CopyOption) error {
2018-08-09 07:30:44 -04:00
var handler copyHandler
2017-06-04 15:32:01 -04:00
for _, option := range options {
2018-08-09 07:30:44 -04:00
option(&handler)
2017-06-04 15:32:01 -04:00
}
2018-08-09 07:30:44 -04:00
err := copyInternal(reader, writer, &handler)
2017-06-04 15:32:01 -04:00
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)
}