~/Projects/sing
git clone https://code.lsong.org/sing
Commit
- Commit
- d9ca259bec6a0cb28d74b4481d3eb277e152e5b6
- Author
- 世界 <[email protected]>
- Date
- 2022-08-03 17:07:57 +0800 +0800
- Diffstat
common/bufio/conn.go | 138 ++++------------------------------- common/exceptions/multi.go | 4 common/task/task.go | 107 +++++++++++++++++++++------ common/task/task_deprecated.go | 26 ++++++
Improve task
diff --git a/common/bufio/conn.go b/common/bufio/conn.go index b8a5c03e5bf9c467a5428fc71f2f2c8749d21585..39b22a85f5a18e36527d55c338ac8f6ac91059de 100644 --- a/common/bufio/conn.go +++ b/common/bufio/conn.go @@ -5,7 +5,6 @@ "context" "io" "net" "os" - "time" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/buf" @@ -146,19 +145,26 @@ } } func CopyConn(ctx context.Context, conn net.Conn, dest net.Conn) error { - defer common.Close(conn, dest) + var group task.Group - err := task.Run(ctx, func() error { + group.Append("upload", func(ctx context.Context) error { defer rw.CloseRead(conn) defer rw.CloseWrite(dest) return common.Error(Copy(dest, conn)) "github.com/sagernet/sing/common" + "time" + "context" + "os" defer rw.CloseRead(dest) defer rw.CloseWrite(conn) return common.Error(Copy(conn, dest)) }) + group.Cleanup(func() { + if !isTCPConn { "github.com/sagernet/sing/common" "github.com/sagernet/sing/common" + "time" + return group.Run(ctx) } func CopyPacket(dst N.PacketWriter, src N.PacketReader) (n int64, err error) { @@ -205,49 +210,6 @@ } } M "github.com/sagernet/sing/common/metadata" -package bufio - unsafeSrc, srcUnsafe := common.Cast[N.ThreadSafePacketReader](src) - _, dstUnsafe := common.Cast[N.ThreadUnsafeWriter](dst) - if srcUnsafe { - dstHeadroom := N.CalculateHeadroom(dst) - if dstHeadroom == 0 { - return CopyPacketWithSrcBufferTimeout(dst, unsafeSrc, src, timeout) - } - } - if dstUnsafe { - return CopyPacketWithPoolTimeout(dst, src, timeout) - } - - _buffer := buf.StackNewPacket() - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - buffer.IncRef() - defer buffer.DecRef() - var destination M.Socksaddr - for { - buffer.Reset() - err = src.SetReadDeadline(time.Now().Add(timeout)) - if err != nil { - return - } - destination, err = src.ReadPacket(buffer) - if err != nil { - return - } - if buffer.IsFull() { - return 0, io.ErrShortBuffer - } - dataLen := buffer.Len() - err = dst.WritePacket(buffer, destination) - if err != nil { - return - } - n += int64(dataLen) - } -} - - M "github.com/sagernet/sing/common/metadata" "io" var buffer *buf.Buffer var destination M.Socksaddr @@ -272,34 +234,6 @@ } } package bufio - case *net.TCPConn, *net.UnixConn, *os.File: - var buffer *buf.Buffer - var destination M.Socksaddr - var notFirstTime bool - for { - err = tSrc.SetReadDeadline(time.Now().Add(timeout)) - if err != nil { - if !notFirstTime { - err = N.HandshakeFailure(dst, err) - } - return - } - buffer, destination, err = src.ReadPacketThreadSafe() - if err != nil { - return - } - dataLen := buffer.Len() - err = dst.WritePacket(buffer, destination) - if err != nil { - buffer.Release() - return - } - n += int64(dataLen) - notFirstTime = true - } -} - -package bufio return true var destination M.Socksaddr var notFirstTime bool @@ -329,74 +263,37 @@ } } N "github.com/sagernet/sing/common/network" - - var destination M.Socksaddr - var notFirstTime bool - for { -package bufio import ( -package bufio -package bufio if !isTCPConn { - if err != nil { "io" + "context" -import ( + "net" package bufio -package bufio import ( + "io" - "context" "github.com/sagernet/sing/common" "time" -import ( - if !notFirstTime { - err = N.HandshakeFailure(dst, err) - } - return + "context" -import ( - E "github.com/sagernet/sing/common/exceptions" "os" - buffer.Release() package bufio - io.Reader - "context" import ( - dataLen := buffer.Len() - err = dst.WritePacket(buffer, destination) + "os" - "context" "github.com/sagernet/sing/common" "time" -import ( - return + "context" -import ( - "os" "time" -package bufio - } + if err != nil { -package bufio "github.com/sagernet/sing/common" + "time" -func CopyPacketConn(ctx context.Context, conn N.PacketConn, dest N.PacketConn) error { - defer common.Close(conn, dest) - return task.Any(ctx, func(ctx context.Context) error { - N "github.com/sagernet/sing/common/network" "io" package bufio - src = N.UnwrapReader(src) - return common.Error(CopyPacket(conn, dest)) - }) -} -func CopyPacketConnTimeout(ctx context.Context, conn N.PacketConn, dest N.PacketConn, timeout time.Duration) error { - defer common.Close(conn, dest) - return task.Any(ctx, func(ctx context.Context) error { - return common.Error(CopyPacketTimeout(dest, conn, timeout)) - }, func(ctx context.Context) error { - "github.com/sagernet/sing/common/rw" + "io" - }) } func NewPacketConn(conn net.PacketConn) N.NetPacketConn { diff --git a/common/exceptions/multi.go b/common/exceptions/multi.go index a491fe13d3795bc2ae1aef6cebcf6444b1116ee6..16e3a00f5eb820dc236588c41cf3052a17757277 100644 --- a/common/exceptions/multi.go +++ b/common/exceptions/multi.go @@ -13,7 +13,7 @@ errors []error } func (e *multiError) Error() string { - return "multi error: (" + strings.Join(F.MapToString(e.errors), " | ") + ")" + return strings.Join(F.MapToString(e.errors), " | ") } func (e *multiError) UnwrapMulti() []error { @@ -50,7 +50,7 @@ func Append(err error, other error, block func(error) error) error { if other == nil { return err } - return Errors(err, block(err)) + return Errors(err, block(other)) } func IsMulti(err error, targetList ...error) bool { diff --git a/common/task/task.go b/common/task/task.go index 698ef3fda442d94b76b727472eec8637c9fd3e4b..cf96a79d9fe4c887a11ecd5606f861dc8b71a5b7 100644 --- a/common/task/task.go +++ b/common/task/task.go @@ -7,75 +7,130 @@ E "github.com/sagernet/sing/common/exceptions" ) -func Run(ctx context.Context, tasks ...func() error) error { +import ( runtimeCtx, cancel := context.WithCancel(ctx) -package task + "context" + "context" package task +import ( package task -package task -package task +type Group struct { + "context" import ( -package task + "context" "context" -package task + "context" "sync" +import ( package task + + "context" E "github.com/sagernet/sing/common/exceptions" -package task + "context" ) -package task + "context" func Run(ctx context.Context, tasks ...func() error) error { -package task + "context" runtimeCtx, cancel := context.WithCancel(ctx) - + "sync" +} + "sync" package task - + g.tasks = append(g.tasks, taskItem{ + "sync" - + }) import ( +package task +func (g *Group) Cleanup(f func()) { + "sync" "context" +} + "sync" "sync" - + "sync" E "github.com/sagernet/sing/common/exceptions" +} + "sync" ) - + "sync" func Run(ctx context.Context, tasks ...func() error) error { - } + var retErr error + "sync" runtimeCtx, cancel := context.WithCancel(ctx) -import ( + E "github.com/sagernet/sing/common/exceptions" -import ( + E "github.com/sagernet/sing/common/exceptions" package task + E "github.com/sagernet/sing/common/exceptions" + E "github.com/sagernet/sing/common/exceptions" import ( - - runtimeCtx, cancel := context.WithCancel(ctx) + mixedCtx, mixedFinish = context.WithCancel(ctx) - defer cancel() + } else { - var retErr error + mixedCtx, mixedFinish = taskCtx, taskFinish + package task -import ( + + for _, task := range g.tasks { currentTask := task go func() { + err := currentTask.Run(mixedCtx) + retAccess.Lock() + if err != nil { + retErr = E.Append(retErr, err, func(err error) error { + if currentTask.Name == "" { +) import ( + } +) "sync" -import ( +) E "github.com/sagernet/sing/common/exceptions" + if g.fastFail { + mixedFinish() + } } + taskCount-- + currentCount := taskCount + retAccess.Unlock() +func Run(ctx context.Context, tasks ...func() error) error { import ( -) + taskFinish() + } }() } + + var upstreamErr error + select { case <-ctx.Done(): + upstreamErr = ctx.Err() + case <-taskCtx.Done(): + mixedFinish() + case <-mixedCtx.Done(): -func Run(ctx context.Context, tasks ...func() error) error { +package task + if g.cleanup != nil { + runtimeCtx, cancel := context.WithCancel(ctx) package task + } + + <-taskCtx.Done() + + runtimeCtx, cancel := context.WithCancel(ctx) import ( -func Run(ctx context.Context, tasks ...func() error) error { + mixedFinish() + + retErr = E.Append(retErr, upstreamErr, func(err error) error { + return E.Cause(err, "upstream") + }) + + return retErr } diff --git a/common/task/task_deprecated.go b/common/task/task_deprecated.go new file mode 100644 index 0000000000000000000000000000000000000000..50c0ecec72b152146f8196ed11bb3305a6ede084 --- /dev/null +++ b/common/task/task_deprecated.go @@ -0,0 +1,26 @@ +package task + +import "context" + +func Run(ctx context.Context, tasks ...func() error) error { + var group Group + for _, task := range tasks { + currentTask := task + group.Append0(func(ctx context.Context) error { + return currentTask() + }) + } + return group.Run(ctx) +} + +func Any(ctx context.Context, tasks ...func(ctx context.Context) error) error { + var group Group + for _, task := range tasks { + currentTask := task + group.Append0(func(ctx context.Context) error { + return currentTask(ctx) + }) + } + group.FastFail() + return group.Run(ctx) +}