mirror of
https://github.com/tgdrive/teldrive.git
synced 2024-11-14 19:56:33 +08:00
70 lines
1.3 KiB
Go
70 lines
1.3 KiB
Go
package recovery
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/cenkalti/backoff/v4"
|
|
"github.com/go-faster/errors"
|
|
"github.com/gotd/td/bin"
|
|
"github.com/gotd/td/telegram"
|
|
"github.com/gotd/td/tg"
|
|
"github.com/gotd/td/tgerr"
|
|
)
|
|
|
|
func hasError(err error, target string) bool {
|
|
for err != nil {
|
|
if err.Error() == target {
|
|
return true
|
|
}
|
|
if unwrapper, ok := err.(interface{ Unwrap() error }); ok {
|
|
err = unwrapper.Unwrap()
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type recovery struct {
|
|
ctx context.Context
|
|
backoff backoff.BackOff
|
|
}
|
|
|
|
func New(ctx context.Context, backoff backoff.BackOff) telegram.Middleware {
|
|
return &recovery{
|
|
ctx: ctx,
|
|
backoff: backoff,
|
|
}
|
|
}
|
|
|
|
func (r *recovery) Handle(next tg.Invoker) telegram.InvokeFunc {
|
|
return func(ctx context.Context, input bin.Encoder, output bin.Decoder) error {
|
|
|
|
return backoff.RetryNotify(func() error {
|
|
if err := next.Invoke(ctx, input, output); err != nil {
|
|
if r.shouldRecover(err) {
|
|
return errors.Wrap(err, "recover")
|
|
}
|
|
|
|
return backoff.Permanent(err)
|
|
}
|
|
|
|
return nil
|
|
}, r.backoff, nil)
|
|
}
|
|
}
|
|
|
|
func (r *recovery) shouldRecover(err error) bool {
|
|
select {
|
|
case <-r.ctx.Done():
|
|
return false
|
|
default:
|
|
}
|
|
|
|
//recover only if context is not cancelled and error is not a rpc error
|
|
isContextErr := hasError(err, "context canceled")
|
|
|
|
_, ok := tgerr.As(err)
|
|
|
|
return !isContextErr && !ok
|
|
}
|