Proactive repairs
This commit is contained in:
@@ -2,6 +2,9 @@ package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -29,6 +32,20 @@ type HTTPClient struct {
|
||||
log *logutil.Logger
|
||||
}
|
||||
|
||||
// {
|
||||
// "error": "infringing_file",
|
||||
// "error_code": 35
|
||||
// }
|
||||
|
||||
type ErrorResponse struct {
|
||||
Message string `json:"error"`
|
||||
Code int `json:"error_code"`
|
||||
}
|
||||
|
||||
func (e *ErrorResponse) Error() string {
|
||||
return fmt.Sprintf("api response error: %s (code: %d)", e.Message, e.Code)
|
||||
}
|
||||
|
||||
func NewHTTPClient(token string, maxRetries int, timeoutSecs int, cfg config.ConfigInterface, log *logutil.Logger) *HTTPClient {
|
||||
client := HTTPClient{
|
||||
bearerToken: token,
|
||||
@@ -46,22 +63,42 @@ func NewHTTPClient(token string, maxRetries int, timeoutSecs int, cfg config.Con
|
||||
},
|
||||
getRetryIncr: func(resp *http.Response, hasRangeHeader bool, err error) int {
|
||||
if resp != nil {
|
||||
if resp.StatusCode == 429 || resp.StatusCode == 400 || resp.StatusCode == 403 {
|
||||
return 1 // retry but don't increment attempt
|
||||
if resp.StatusCode == 429 {
|
||||
return 1
|
||||
}
|
||||
if resp.StatusCode != http.StatusPartialContent && hasRangeHeader {
|
||||
return 1
|
||||
}
|
||||
return 0 // don't retry
|
||||
} else if err != nil {
|
||||
errStr := err.Error()
|
||||
if strings.Contains(errStr, "EOF") || strings.Contains(errStr, "connection reset") || strings.Contains(errStr, "no such host") {
|
||||
return 1 // retry but don't increment attempt
|
||||
} else {
|
||||
return RATE_LIMIT_FACTOR
|
||||
log.Errorf("Client request error: %s", err.Error())
|
||||
if strings.Contains(err.Error(), "api response error") {
|
||||
if apiErr, ok := err.(*ErrorResponse); ok {
|
||||
switch apiErr.Code {
|
||||
case -1: // Internal error
|
||||
return 1
|
||||
case 5: // Slow down
|
||||
return 1
|
||||
case 6: // Ressource unreachable
|
||||
return 1
|
||||
case 17: // Hoster in maintenance
|
||||
return 1
|
||||
case 19: // Hoster temporarily unavailable
|
||||
return 1
|
||||
case 25: // Service unavailable
|
||||
return 1
|
||||
case 34: // Too many requests
|
||||
return 1
|
||||
case 36: // Fair Usage Limit
|
||||
return 1
|
||||
default:
|
||||
return 0 // don't retry
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
return RATE_LIMIT_FACTOR // retry and increment attempt
|
||||
return RATE_LIMIT_FACTOR
|
||||
},
|
||||
cfg: cfg,
|
||||
ipv6: cmap.New[string](),
|
||||
@@ -116,6 +153,16 @@ func (r *HTTPClient) Do(req *http.Request) (*http.Response, error) {
|
||||
attempt := 0
|
||||
for {
|
||||
resp, err = r.client.Do(req)
|
||||
if resp != nil && resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusPartialContent {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
if body != nil {
|
||||
var errResp ErrorResponse
|
||||
jsonErr := json.Unmarshal(body, &errResp)
|
||||
if jsonErr == nil {
|
||||
err = &errResp
|
||||
}
|
||||
}
|
||||
}
|
||||
if incr := r.getRetryIncr(resp, hasRangeHeader, err); incr > 0 {
|
||||
attempt += incr
|
||||
if attempt > r.maxRetries {
|
||||
|
||||
Reference in New Issue
Block a user