-
Notifications
You must be signed in to change notification settings - Fork 0
/
handlers.go
136 lines (115 loc) · 4.12 KB
/
handlers.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package grpcerrors
import (
"github.com/srvc/fail/v4"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// UnaryServerErrorHandler is the interface that can handle errors on a gRPC unary server
type UnaryServerErrorHandler interface {
HandleUnaryServerError(context.Context, interface{}, *grpc.UnaryServerInfo, error) error
}
// StreamServerErrorHandler is the interface that can handle errors on a gRPC stream server
type StreamServerErrorHandler interface {
HandleStreamServerError(context.Context, interface{}, interface{}, *grpc.StreamServerInfo, error) error
}
// ErrorHandlerFunc is a function that called by interceptors when specified erorrs are detected.
type ErrorHandlerFunc func(context.Context, error) error
// FailHandlerFunc is a function that called by interceptors when specified application erorrs are detected.
type FailHandlerFunc func(context.Context, *fail.Error) error
type failHandler struct {
f FailHandlerFunc
}
func (h *failHandler) HandleUnaryServerError(c context.Context, req interface{}, info *grpc.UnaryServerInfo, err error) error {
return h.handleError(c, err)
}
func (h *failHandler) HandleStreamServerError(c context.Context, req interface{}, resp interface{}, info *grpc.StreamServerInfo, err error) error {
return h.handleError(c, err)
}
func (h *failHandler) handleError(c context.Context, err error) error {
fErr := fail.Unwrap(err)
if fErr != nil {
return h.f(c, fErr)
}
return err
}
// WithFailHandler returns a new error handler function for handling errors wrapped with fail.Error.
func WithFailHandler(f FailHandlerFunc) interface {
UnaryServerErrorHandler
StreamServerErrorHandler
} {
return &failHandler{f: f}
}
type notWrappedHandler struct {
f ErrorHandlerFunc
}
func (h *notWrappedHandler) HandleUnaryServerError(c context.Context, req interface{}, info *grpc.UnaryServerInfo, err error) error {
return h.handleError(c, err)
}
func (h *notWrappedHandler) HandleStreamServerError(c context.Context, req interface{}, resp interface{}, info *grpc.StreamServerInfo, err error) error {
return h.handleError(c, err)
}
func (h *notWrappedHandler) handleError(c context.Context, err error) error {
fErr := fail.Unwrap(err)
if fErr == nil {
return h.f(c, err)
}
return err
}
// WithNotWrappedErrorHandler returns a new error handler function for handling not wrapped errors.
func WithNotWrappedErrorHandler(f ErrorHandlerFunc) interface {
UnaryServerErrorHandler
StreamServerErrorHandler
} {
return ¬WrappedHandler{f: f}
}
// WithReportableErrorHandler returns a new error handler function for handling errors annotated with the reportability.
func WithReportableErrorHandler(f FailHandlerFunc) interface {
UnaryServerErrorHandler
StreamServerErrorHandler
} {
return WithFailHandler(func(c context.Context, err *fail.Error) error {
if err.Ignorable {
return err
}
return f(c, err)
})
}
// CodeMap maps any status codes to gRPC's `codes.Code`s.
type CodeMap map[interface{}]codes.Code
// WithCodeMap returns a new error handler function for mapping status codes to gRPC's one.
func WithCodeMap(m CodeMap) interface {
UnaryServerErrorHandler
StreamServerErrorHandler
} {
return WithFailHandler(func(c context.Context, err *fail.Error) error {
if c, ok := m[err.Code]; ok {
return status.Error(c, err.Error())
}
return err
})
}
// CodeMapFunc returns gRPC's `codes.Code`s from given any codes.
type CodeMapFunc func(code interface{}) codes.Code
// WithCodeMapper returns a new error handler function for mapping status codes to gRPC's one with given function.
func WithCodeMapper(mapFn CodeMapFunc) interface {
UnaryServerErrorHandler
StreamServerErrorHandler
} {
return WithFailHandler(func(c context.Context, err *fail.Error) error {
return status.Error(mapFn(err.Code), err.Error())
})
}
// WithGrpcStatusUnwrapper returns unwrapped error if this has a gRPC status.
func WithGrpcStatusUnwrapper() interface {
UnaryServerErrorHandler
StreamServerErrorHandler
} {
return WithFailHandler(func(c context.Context, err *fail.Error) error {
if _, ok := status.FromError(err.Err); ok {
return err.Err
}
return err
})
}