| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- 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.ReadMultiBuffer()
- 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.WriteMultiBuffer(mb)
- if err != nil {
- for _, handler := range h.onWriteError {
- err = handler(err)
- }
- }
- return err
- }
- // SizeCounter is for counting bytes copied by Copy().
- type SizeCounter struct {
- Size int64
- }
- // CopyOption is an option for copying data.
- type CopyOption func(*copyHandler)
- // IgnoreReaderError is a CopyOption that ignores errors from reader. Copy will continue in such case.
- func IgnoreReaderError() CopyOption {
- return func(handler *copyHandler) {
- handler.onReadError = append(handler.onReadError, func(err error) error {
- return nil
- })
- }
- }
- // IgnoreWriterError is a CopyOption that ignores errors from writer. Copy will continue in such case.
- func IgnoreWriterError() CopyOption {
- return func(handler *copyHandler) {
- handler.onWriteError = append(handler.onWriteError, func(err error) error {
- return nil
- })
- }
- }
- // 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())
- })
- }
- }
- 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
- }
- } else if err != nil {
- return 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 {
- 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
- }
|