2020-07-11 13:49:07 -04:00
|
|
|
package reddit
|
2020-05-16 11:53:15 -04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
2020-09-21 23:28:05 -04:00
|
|
|
"strings"
|
2020-09-28 22:13:50 -04:00
|
|
|
"time"
|
2020-05-16 11:53:15 -04:00
|
|
|
)
|
|
|
|
|
2020-08-11 19:10:23 -04:00
|
|
|
// APIError is an error coming from Reddit.
|
2020-07-11 14:11:41 -04:00
|
|
|
type APIError struct {
|
2020-05-16 11:53:15 -04:00
|
|
|
Label string
|
|
|
|
Reason string
|
|
|
|
Field string
|
|
|
|
}
|
|
|
|
|
2020-07-11 14:11:41 -04:00
|
|
|
func (e *APIError) Error() string {
|
2020-07-03 00:51:55 -04:00
|
|
|
return fmt.Sprintf("field %q caused %s: %s", e.Field, e.Label, e.Reason)
|
2020-05-16 11:53:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
2020-07-11 14:11:41 -04:00
|
|
|
func (e *APIError) UnmarshalJSON(data []byte) error {
|
2020-08-11 19:10:23 -04:00
|
|
|
var info [3]string
|
2020-05-16 11:53:15 -04:00
|
|
|
|
|
|
|
err := json.Unmarshal(data, &info)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
e.Label = info[0]
|
|
|
|
e.Reason = info[1]
|
|
|
|
e.Field = info[2]
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-11 19:10:23 -04:00
|
|
|
// JSONErrorResponse is an error response that sometimes gets returned with a 200 code.
|
2020-05-16 11:53:15 -04:00
|
|
|
type JSONErrorResponse struct {
|
2020-08-11 19:10:23 -04:00
|
|
|
// HTTP response that caused this error.
|
2020-05-16 11:53:15 -04:00
|
|
|
Response *http.Response `json:"-"`
|
|
|
|
|
2020-08-17 22:01:04 -04:00
|
|
|
JSON struct {
|
2020-07-11 14:11:41 -04:00
|
|
|
Errors []APIError `json:"errors,omitempty"`
|
2020-08-17 22:01:04 -04:00
|
|
|
} `json:"json"`
|
2020-05-16 11:53:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *JSONErrorResponse) Error() string {
|
2020-09-21 23:28:05 -04:00
|
|
|
errorMessages := make([]string, len(r.JSON.Errors))
|
|
|
|
for i, err := range r.JSON.Errors {
|
|
|
|
errorMessages[i] = err.Error()
|
2020-05-16 11:53:15 -04:00
|
|
|
}
|
2020-08-17 22:01:04 -04:00
|
|
|
|
2020-05-16 11:53:15 -04:00
|
|
|
return fmt.Sprintf(
|
2020-08-17 22:01:04 -04:00
|
|
|
"%s %s: %d %s",
|
2020-09-21 23:28:05 -04:00
|
|
|
r.Response.Request.Method, r.Response.Request.URL, r.Response.StatusCode, strings.Join(errorMessages, ";"),
|
2020-05-16 11:53:15 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// An ErrorResponse reports the error caused by an API request
|
|
|
|
type ErrorResponse struct {
|
|
|
|
// HTTP response that caused this error
|
|
|
|
Response *http.Response `json:"-"`
|
|
|
|
|
|
|
|
// Error message
|
|
|
|
Message string `json:"message"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *ErrorResponse) Error() string {
|
|
|
|
return fmt.Sprintf(
|
2020-08-17 22:01:04 -04:00
|
|
|
"%s %s: %d %s",
|
2020-05-16 11:53:15 -04:00
|
|
|
r.Response.Request.Method, r.Response.Request.URL, r.Response.StatusCode, r.Message,
|
|
|
|
)
|
|
|
|
}
|
2020-08-11 19:10:23 -04:00
|
|
|
|
2020-09-28 22:13:50 -04:00
|
|
|
// RateLimitError occurs when the client is sending too many requests to Reddit in a given time frame.
|
|
|
|
type RateLimitError struct {
|
|
|
|
// Rate specifies the last known rate limit for the client
|
|
|
|
Rate Rate
|
|
|
|
// HTTP response that caused this error
|
|
|
|
Response *http.Response
|
|
|
|
// Error message
|
|
|
|
Message string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *RateLimitError) Error() string {
|
|
|
|
return fmt.Sprintf(
|
|
|
|
"%s %s: %d %s %s",
|
|
|
|
e.Response.Request.Method, e.Response.Request.URL, e.Response.StatusCode, e.Message, e.formateRateReset(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *RateLimitError) formateRateReset() string {
|
|
|
|
d := time.Until(e.Rate.Reset).Round(time.Second)
|
|
|
|
|
|
|
|
isNegative := d < 0
|
|
|
|
if isNegative {
|
|
|
|
d *= -1
|
|
|
|
}
|
|
|
|
|
|
|
|
if isNegative {
|
|
|
|
return fmt.Sprintf("[rate limit was reset %s ago]", d)
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("[rate limit will reset in %s]", d)
|
|
|
|
}
|