1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-12-21 09:36:34 -05:00

refine copy handler

This commit is contained in:
Darien Raymond 2017-06-04 21:32:01 +02:00
parent b86b998a20
commit 07847576b5
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
2 changed files with 100 additions and 88 deletions

100
common/buf/copy.go Normal file
View File

@ -0,0 +1,100 @@
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) {
mb, err := reader.Read()
if err != nil {
for _, handler := range h.onReadError {
err = handler(err)
}
}
return mb, err
}
func (h *copyHandler) writeTo(writer Writer, mb MultiBuffer) error {
err := writer.Write(mb)
if err != nil {
for _, handler := range h.onWriteError {
err = handler(err)
}
}
return err
}
type CopyOption func(*copyHandler)
func IgnoreReaderError() CopyOption {
return func(handler *copyHandler) {
handler.onReadError = append(handler.onReadError, func(err error) error {
return nil
})
}
}
func IgnoreWriterError() CopyOption {
return func(handler *copyHandler) {
handler.onWriteError = append(handler.onWriteError, func(err error) error {
return nil
})
}
}
func UpdateActivity(timer signal.ActivityTimer) CopyOption {
return func(handler *copyHandler) {
handler.onData = append(handler.onData, func(MultiBuffer) {
timer.Update()
})
}
}
func copyInternal(reader Reader, writer Writer, handler *copyHandler) error {
for {
buffer, err := handler.readFrom(reader)
if err != nil {
return err
}
if buffer.IsEmpty() {
buffer.Release()
continue
}
for _, handler := range handler.onData {
handler(buffer)
}
if err := handler.writeTo(writer, buffer); err != nil {
buffer.Release()
return err
}
}
}
// Copy dumps all payload from reader to writer or stops when an error occurs.
// ActivityTimer gets updated as soon as there is a payload.
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
}

View File

@ -3,9 +3,6 @@ package buf
import (
"io"
"time"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/signal"
)
// Reader extends io.Reader with alloc.Buffer.
@ -47,91 +44,6 @@ func ReadAtLeastFrom(reader io.Reader, size int) Supplier {
}
}
type copyHandler struct {
onReadError func(error) error
onData func()
onWriteError func(error) error
}
func (h *copyHandler) readFrom(reader Reader) (MultiBuffer, error) {
mb, err := reader.Read()
if err != nil && h.onReadError != nil {
err = h.onReadError(err)
}
return mb, err
}
func (h *copyHandler) writeTo(writer Writer, mb MultiBuffer) error {
err := writer.Write(mb)
if err != nil && h.onWriteError != nil {
err = h.onWriteError(err)
}
return err
}
type CopyOption func(*copyHandler)
func IgnoreReaderError() CopyOption {
return func(handler *copyHandler) {
handler.onReadError = func(err error) error {
return nil
}
}
}
func IgnoreWriterError() CopyOption {
return func(handler *copyHandler) {
handler.onWriteError = func(err error) error {
return nil
}
}
}
func UpdateActivity(timer signal.ActivityTimer) CopyOption {
return func(handler *copyHandler) {
handler.onData = func() {
timer.Update()
}
}
}
func copyInternal(reader Reader, writer Writer, handler *copyHandler) error {
for {
buffer, err := handler.readFrom(reader)
if err != nil {
return err
}
if buffer.IsEmpty() {
buffer.Release()
continue
}
if handler.onData != nil {
handler.onData()
}
if err := handler.writeTo(writer, buffer); err != nil {
buffer.Release()
return err
}
}
}
// Copy dumps all payload from reader to writer or stops when an error occurs.
// ActivityTimer gets updated as soon as there is a payload.
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
}
// NewReader creates a new Reader.
// The Reader instance doesn't take the ownership of reader.
func NewReader(reader io.Reader) Reader {