forked from peak/s5cmd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
error.go
105 lines (88 loc) · 2.69 KB
/
error.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package core
import (
"errors"
"fmt"
"strings"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
)
const sdkPanicErrCode = "SdkPanic"
// AcceptableError interface defines an error which is OK-to-have, for things like "cp -n" etc. It should not be treated as an error (regarding the exit code etc)
type AcceptableError interface {
error
Acceptable() bool
}
// AcceptableErrorType embeds the stdlib error interface so that we can have more receivers on it
type AcceptableErrorType struct {
error
}
// NewAcceptableError creates a new AcceptableError
func NewAcceptableError(s string) AcceptableErrorType {
return AcceptableErrorType{errors.New(s)}
}
// Acceptable is always true for errors of AcceptableError type
func (e AcceptableErrorType) Acceptable() bool {
return true
}
// IsRetryableError returns if an error (probably awserr) is retryable, along with an error code
func IsRetryableError(err error) (code string, retryable bool) {
if err == nil {
return
}
code = "UNK"
retryable = request.IsErrorRetryable(err) || request.IsErrorThrottle(err)
if awsErr, ok := err.(awserr.Error); ok {
//fmt.Println("awsErr", awsErr.Code(), awsErr.Message(), awsErr.OrigErr())
errCode := awsErr.Code()
switch errCode {
case "SlowDown", "SerializationError", "RequestError", sdkPanicErrCode, "NoCredentialProviders":
code = errCode
return
}
if origCode, origRetryable := IsRetryableError(awsErr.OrigErr()); origRetryable {
code = origCode
return
}
if reqErr, ok := err.(awserr.RequestFailure); ok {
// A service error occurred
//fmt.Println("reqErr", reqErr.StatusCode(), reqErr.RequestID())
errCode = reqErr.Code()
switch errCode {
case "InternalError", "SerializationError", "RequestError":
code = errCode
return
}
status := reqErr.StatusCode()
switch status {
case 500:
code = fmt.Sprintf("HTTP%d", status)
return
}
}
}
return
}
// CleanupError converts multiline error messages generated by aws-sdk-go into a single line
func CleanupError(err error) (s string) {
s = strings.Replace(err.Error(), "\n", " ", -1)
s = strings.Replace(s, "\t", " ", -1)
s = strings.Replace(s, " ", " ", -1)
s = strings.Replace(s, " ", " ", -1)
s = strings.TrimSpace(s)
return
}
// IsAcceptableError determines if the error is an AcceptableError, and if so, returns the error as such
func IsAcceptableError(err error) AcceptableError {
e, ok := err.(AcceptableError)
if !ok {
return nil
}
return e
}
func recoverer(ch chan error, where string, failed *bool) {
if r := recover(); r != nil {
ch <- awserr.New(sdkPanicErrCode, fmt.Sprintf("Caught %s panic", where), fmt.Errorf("%s: %v", where, r))
f := true
failed = &f
}
}