Return an error for 503

This commit is contained in:
Ben Adrian Sarmiento
2024-06-23 22:08:54 +02:00
parent 8bf39d58de
commit 3abf48514d
10 changed files with 87 additions and 65 deletions

View File

@@ -42,6 +42,15 @@ func (e *ApiErrorResponse) Error() string {
return fmt.Sprintf("api response error: %s (code: %d)", e.Message, e.Code)
}
type DownloadErrorResponse struct {
Message string
Code int
}
func (e *DownloadErrorResponse) Error() string {
return fmt.Sprintf("download response error: %s (code: %d)", e.Message, e.Code)
}
func NewHTTPClient(
token string,
maxRetries int,
@@ -152,13 +161,25 @@ func (r *HTTPClient) Do(req *http.Request) (*http.Response, error) {
// http 4xx and 5xx errors
if resp != nil && resp.StatusCode >= http.StatusBadRequest {
body, _ := io.ReadAll(resp.Body)
if body != nil {
var errResp ApiErrorResponse
jsonErr := json.Unmarshal(body, &errResp)
if jsonErr == nil {
errResp.Message += fmt.Sprintf(" (status code: %d)", resp.StatusCode)
if req.Host == "api.real-debrid.com" {
if body != nil {
var errResp ApiErrorResponse
jsonErr := json.Unmarshal(body, &errResp)
if jsonErr == nil {
errResp.Message += fmt.Sprintf(" (status code: %d)", resp.StatusCode)
} else {
errResp.Message = string(body)
errResp.Code = resp.StatusCode
}
err = &errResp
}
} else {
// download servers
errResp := DownloadErrorResponse{
Message: resp.Header.Get("X-Error"),
Code: resp.StatusCode,
}
err = &errResp
}
}
@@ -177,10 +198,6 @@ func (r *HTTPClient) Do(req *http.Request) (*http.Response, error) {
break
}
}
okWithTimeout := strings.HasSuffix(req.URL.Path, "unrestrict/link") && strings.HasSuffix(req.URL.Path, "torrents/addMagnet")
if err != nil && strings.Contains(err.Error(), "timeout") && req.Host == "api.real-debrid.com" && !okWithTimeout {
r.log.Warnf("Adjust your API timeout settings, request to %s timed out", req.URL.String())
}
return resp, err
}
@@ -206,30 +223,36 @@ func (r *HTTPClient) shouldRetry(req *http.Request, resp *http.Response, err err
if strings.HasSuffix(req.URL.Path, "torrents/addMagnet") {
return -1 // don't retry to prevent duplicate torrents
}
if err != nil && strings.HasPrefix(err.Error(), "api response error:") {
if apiErr, ok := err.(*ApiErrorResponse); ok {
switch apiErr.Code {
case -1: // Internal error
return 1
case 5: // Slow down (retry infinitely), default: 4 secs
time.Sleep(time.Duration(rateLimitSleep) * time.Second)
return 0
case 6: // Ressource unreachable
return 1
case 17: // Hoster in maintenance
return 1
case 18: // Hoster limit reached
return 1
case 25: // Service unavailable
return 1
case 34: // Too many requests (retry infinitely), default: 4 secs
time.Sleep(time.Duration(rateLimitSleep) * time.Second)
return 0
case 36: // Fair Usage Limit
return 1
default:
return -1 // don't retry
}
if apiErr, ok := err.(*ApiErrorResponse); ok {
switch apiErr.Code {
case -1: // Internal error
return 1
case 5: // Slow down (retry infinitely), default: 4 secs
time.Sleep(time.Duration(rateLimitSleep) * time.Second)
return 0
case 6: // Ressource unreachable
return 1
case 17: // Hoster in maintenance
return 1
case 18: // Hoster limit reached
return 1
case 25: // Service unavailable
return 1
case 34: // Too many requests (retry infinitely), default: 4 secs
time.Sleep(time.Duration(rateLimitSleep) * time.Second)
return 0
case 36: // Fair Usage Limit
time.Sleep(time.Duration(rateLimitSleep) * time.Second)
return 1
default:
return -1 // don't retry
}
} else if downloadErr, ok := err.(*DownloadErrorResponse); ok {
switch downloadErr.Code {
case http.StatusServiceUnavailable: // Service unavailable
return -1
default:
return 1
}
}
if err != nil && strings.Contains(err.Error(), "timeout") {
@@ -270,12 +293,11 @@ func backoffFunc(attempt int) time.Duration {
return time.Duration(backoff) * time.Second
}
func (r *HTTPClient) CanFetchFirstByte(url string) bool {
req, err := http.NewRequest("GET", url, nil)
func (r *HTTPClient) VerifyURL(url string) bool {
req, err := http.NewRequest(http.MethodHead, url, nil)
if err != nil {
return false
}
req.Header.Set("Range", "bytes=0-0")
timeout := time.Duration(r.timeoutSecs) * time.Second
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
@@ -283,7 +305,7 @@ func (r *HTTPClient) CanFetchFirstByte(url string) bool {
resp, _ := r.Do(req)
if resp != nil {
defer resp.Body.Close()
return resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusPartialContent
return resp.StatusCode == http.StatusOK
}
return false
}