Add multi error

This commit is contained in:
世界 2022-07-06 20:48:55 +08:00
parent f00396c60e
commit f8356c256f
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
10 changed files with 141 additions and 102 deletions

View file

@ -1,34 +0,0 @@
name: Linter
on:
push:
branches:
- dev
paths:
- "**/*.go"
- ".github/workflows/linter.yml"
pull_request:
types: [ opened, synchronize, reopened ]
paths:
- "**/*.go"
- ".github/workflows/linter.yml"
jobs:
lint:
if: github.repository == 'sagernet/sing'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Get latest go version
id: version
run: |
echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g')
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ steps.version.outputs.go_version }}
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest

View file

@ -78,6 +78,20 @@ func Filter[T any](arr []T, block func(it T) bool) []T {
return retArr
}
func FilterNotNil[T any](arr []T) []T {
return Filter(arr, func(it T) bool {
var anyIt any = it
return anyIt != nil
})
}
func FilterNotDefault[T comparable](arr []T) []T {
var defaultValue T
return Filter(arr, func(it T) bool {
return it != defaultValue
})
}
func Find[T any](arr []T, block func(it T) bool) T {
for _, it := range arr {
if block(it) {
@ -163,6 +177,7 @@ func Must2(_, _ any, err error) {
}
}
// Deprecated: use E.Errors
func AnyError(errs ...error) error {
for _, err := range errs {
if err != nil {

View file

@ -0,0 +1,17 @@
package exceptions
type causeError struct {
message string
cause error
}
func (e *causeError) Error() string {
if e.cause == nil {
return e.message
}
return e.message + ": " + e.cause.Error()
}
func (e *causeError) Unwrap() error {
return e.cause
}

View file

@ -8,39 +8,16 @@ import (
"net"
"os"
"github.com/sagernet/sing/common"
F "github.com/sagernet/sing/common/format"
)
type causeError struct {
message string
cause error
type Handler interface {
NewError(ctx context.Context, err error)
}
func (e *causeError) Error() string {
if e.cause == nil {
return e.message
}
return e.message + ": " + e.cause.Error()
}
func (e *causeError) Unwrap() error {
return e.cause
}
type extendedError struct {
message string
cause error
}
func (e *extendedError) Error() string {
if e.cause == nil {
return e.message
}
return e.cause.Error() + ": " + e.message
}
func (e *extendedError) Unwrap() error {
return e.cause
type MultiError interface {
UnwrapMulti() []error
}
func New(message ...any) error {
@ -55,23 +32,17 @@ func Extend(cause error, message ...any) error {
return &extendedError{F.ToString(message...), cause}
}
type HasInnerError interface {
Unwrap() error
}
func Unwrap(err error) error {
for {
inner, ok := err.(HasInnerError)
if !ok {
break
}
innerErr := inner.Unwrap()
if innerErr == nil {
break
}
err = innerErr
func Errors(errors ...error) error {
errors = common.FilterNotNil(errors)
switch len(errors) {
case 0:
return nil
case 1:
return errors[0]
}
return &multiError{
errors: errors,
}
return err
}
func IsCanceled(err error) bool {
@ -81,24 +52,3 @@ func IsCanceled(err error) bool {
func IsClosed(err error) bool {
return errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, os.ErrClosed)
}
type TimeoutError interface {
Timeout() bool
}
func IsTimeout(err error) bool {
if unwrapErr := errors.Unwrap(err); unwrapErr != nil {
err = unwrapErr
}
if ne, ok := err.(*os.SyscallError); ok {
err = ne.Err
}
if timeoutErr, isTimeoutErr := err.(TimeoutError); isTimeoutErr {
return timeoutErr.Timeout()
}
return false
}
type Handler interface {
NewError(ctx context.Context, err error)
}

View file

@ -0,0 +1,17 @@
package exceptions
type extendedError struct {
message string
cause error
}
func (e *extendedError) Error() string {
if e.cause == nil {
return e.message
}
return e.cause.Error() + ": " + e.message
}
func (e *extendedError) Unwrap() error {
return e.cause
}

View file

@ -0,0 +1,20 @@
package exceptions
type HasInnerError interface {
Unwrap() error
}
func Unwrap(err error) error {
for {
inner, ok := err.(HasInnerError)
if !ok {
break
}
innerErr := inner.Unwrap()
if innerErr == nil {
break
}
err = innerErr
}
return err
}

View file

@ -0,0 +1,31 @@
package exceptions
import (
"errors"
"strings"
"github.com/sagernet/sing/common"
F "github.com/sagernet/sing/common/format"
)
type multiError struct {
errors []error
}
func (e *multiError) Error() string {
return "multi error: (" + strings.Join(common.Map(e.errors, F.ToString0[error]), " | ") + ")"
}
func (e *multiError) Unwrap() error {
return e.errors[0]
}
func (e *multiError) UnwrapMulti() []error {
return e.errors
}
func (e *multiError) Is(err error) bool {
return common.Any(e.errors, func(it error) bool {
return errors.Is(it, err)
})
}

View file

@ -0,0 +1,23 @@
package exceptions
import (
"errors"
"os"
)
type TimeoutError interface {
Timeout() bool
}
func IsTimeout(err error) bool {
if unwrapErr := errors.Unwrap(err); unwrapErr != nil {
err = unwrapErr
}
if ne, ok := err.(*os.SyscallError); ok {
err = ne.Err
}
if timeoutErr, isTimeoutErr := err.(TimeoutError); isTimeoutErr {
return timeoutErr.Timeout()
}
return false
}

View file

@ -118,7 +118,7 @@ func HandleConnection(ctx context.Context, conn net.Conn, reader *std_bufio.Read
response, err := httpClient.Do(request)
if err != nil {
return common.AnyError(innerErr, err, responseWith(request, http.StatusBadGateway).Write(conn))
return E.Errors(innerErr, err, responseWith(request, http.StatusBadGateway).Write(conn))
}
removeHopByHopHeaders(response.Header)
@ -133,7 +133,7 @@ func HandleConnection(ctx context.Context, conn net.Conn, reader *std_bufio.Read
err = response.Write(conn)
if err != nil {
return common.AnyError(innerErr, err)
return E.Errors(innerErr, err)
}
if !keepAlive {

View file

@ -224,7 +224,7 @@ func HandleConnection0(ctx context.Context, conn net.Conn, version byte, authent
close(done)
}()
err = common.Error(io.Copy(io.Discard, conn))
return common.AnyError(innerError, err)
return E.New(innerError, err)
default:
err = socks5.WriteResponse(conn, socks5.Response{
ReplyCode: socks5.ReplyCodeUnsupported,