/
stack.go
119 lines (108 loc) · 3.02 KB
/
stack.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package errors
import (
"strings"
"encoding/json"
"errors"
"github.com/miekg/dns"
"net"
"fmt"
)
type ErrorStack struct {
errors []error
}
func NewErrorStack(err error) *ErrorStack {
s := new(ErrorStack)
s.Push(err)
return s
}
func (es *ErrorStack) Copy() *ErrorStack {
newStack := new(ErrorStack)
for _, err := range es.errors {
// provision for when an error type will require a deepcopy
switch typedErr := err.(type) {
/* case *NXDomainError:
newStack.errors = append(newStack.errors, err)
case *ServfailError:
newStack.errors = append(newStack.errors, err)
case *NoNameServerError:
newStack.errors = append(newStack.errors, err)
case *TimeoutError:
newStack.errors = append(newStack.errors, err)*/
default:
_ = typedErr
newStack.errors = append(newStack.errors, err)
}
}
return newStack
}
func (es *ErrorStack) MarshalJSON() ([]byte, error) {
var ses []interface{}
for _, err := range es.errors {
switch typedErr := err.(type) {
case *NXDomainError:
ses = append(ses, typedErr)
case *ServfailError:
ses = append(ses, typedErr)
case *NoNameServerError:
ses = append(ses, typedErr)
default:
ses = append(ses, typedErr.Error())
}
}
return json.Marshal(ses)
}
func (es *ErrorStack) UnmarshalJSON(bstr []byte) error {
var ses []interface{}
if err := json.Unmarshal(bstr, &ses) ; err != nil {
return err
}
for _, err := range ses {
switch typedErr := err.(type) {
case string:
es.errors = append(es.errors, errors.New(typedErr))
case map[string]interface{}:
if typeVal, ok := typedErr["type"] ; ok {
if typeVal.(string) == dns.RcodeToString[dns.RcodeServerFailure] {
es.errors = append(es.errors, NewServfailError(typedErr["qname"].(string), dns.StringToType[typedErr["qtype"].(string)], net.ParseIP(typedErr["ip"].(string)), STR_TO_PROTO[typedErr["protocol"].(string)]))
} else if typeVal.(string) == dns.RcodeToString[dns.RcodeNameError] {
es.errors = append(es.errors, NewNXDomainError(typedErr["qname"].(string), dns.StringToType[typedErr["qtype"].(string)], net.ParseIP(typedErr["ip"].(string)), STR_TO_PROTO[typedErr["protocol"].(string)]))
} else {
panic(fmt.Sprintf("missing case: type unknown: %s", typeVal))
}
} else if name, ok := typedErr["name"] ; ok {
es.errors = append(es.errors, NewNoNameServerError(name.(string)))
}
default:
panic("missing case: not a string nor a map?")
}
}
return nil
}
func (es *ErrorStack) Push(err error) {
es.errors = append(es.errors, err)
}
func (es *ErrorStack) OriginalError() error {
if len(es.errors) > 0 {
return es.errors[0]
}
return nil
}
func (es *ErrorStack) LatestError() error {
if len(es.errors) > 0 {
return es.errors[len(es.errors)-1]
}
return nil
}
func (es *ErrorStack) Error() string {
errCount := len(es.errors)
l := make([]string, errCount)
if errCount == 1 {
l[0] = es.errors[0].Error()
} else {
for i := 0; i < len(es.errors)/2; i++ {
l[i] = es.errors[errCount-1-i].Error()
l[errCount-1-i] = es.errors[i].Error()
}
}
return strings.Join(l, ", ")
}