package downloader
import (
"context"
"net"
"github.com/go-faster/errors"
"github.com/gotd/td/exchange"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
)
const maxRetryAttempts = 20
func retryLimitErr (op string , attempts int , err error ) error {
return errors .Wrapf (err , "%s: retry limit reached (%d)" , op , attempts )
}
func isCDNFingerprintErr (err error ) bool {
return errors .Is (err , exchange .ErrKeyFingerprintNotFound )
}
func isCDNMasterFallbackErr (err error ) bool {
return tgerr .Is (
err ,
"FILE_TOKEN_INVALID" ,
"REQUEST_TOKEN_INVALID" ,
)
}
func isRetryableTimeout (ctx context .Context , err error ) bool {
if err == nil {
return false
}
if ctx .Err () != nil {
return false
}
if tgerr .Is (err , tg .ErrTimeout ) || errors .Is (err , context .DeadlineExceeded ) {
return true
}
var netErr net .Error
return errors .As (err , &netErr ) && netErr .Timeout ()
}
func retryRequest [T any ](
ctx context .Context ,
op string ,
onRetry func (attempt int , err error ),
fn func () (T , error ),
) (_ T , err error ) {
var zero T
timeoutRetries := 0
retryAttempt := 0
for {
if err := ctx .Err (); err != nil {
return zero , err
}
result , err := fn ()
if flood , waitErr := tgerr .FloodWait (ctx , err ); waitErr != nil {
if flood {
if ctxErr := ctx .Err (); ctxErr != nil {
return zero , ctxErr
}
retryAttempt ++
if onRetry != nil {
onRetry (retryAttempt , waitErr )
}
continue
}
if isRetryableTimeout (ctx , waitErr ) {
timeoutRetries ++
if timeoutRetries >= maxRetryAttempts {
return zero , retryLimitErr (op , timeoutRetries , waitErr )
}
retryAttempt ++
if onRetry != nil {
onRetry (retryAttempt , waitErr )
}
continue
}
return zero , waitErr
}
return result , nil
}
}
The pages are generated with Golds v0.8.4 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .