-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathhandler.go
More file actions
174 lines (145 loc) · 3.83 KB
/
handler.go
File metadata and controls
174 lines (145 loc) · 3.83 KB
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package fire
import (
"time"
"github.com/256dpi/xo"
)
// A Callback is called during the request processing flow of a controller.
type Callback struct {
// The name.
Name string
// The stage.
Stage Stage
// The matcher that decides whether the callback should be run.
Matcher Matcher
// The handler that gets executed with the context.
//
// If returned errors are marked with Safe() they will be included in the
// returned JSON-API error.
Handler Handler
}
// L is a shorthand type to create a list of callbacks.
type L = []*Callback
// C is a shorthand function to construct a callback. It will also add tracing
// code around the execution of the callback.
func C(name string, s Stage, m Matcher, h Handler) *Callback {
// panic if parameters are not set
if name == "" || m == nil || h == nil {
panic("fire: missing parameters")
}
return &Callback{
Name: name,
Stage: s,
Matcher: m,
Handler: func(ctx *Context) error {
// trace
ctx.Tracer.Push(name)
defer ctx.Tracer.Pop()
// call handler
err := h(ctx)
if err != nil {
return xo.W(err)
}
return nil
},
}
}
// An Action defines a collection or resource action.
type Action struct {
// The allowed methods for this action.
Methods []string
// BodyLimit defines the maximum allowed size of the request body. The
// serve.ByteSize helper can be used to set the value.
//
// Default: 8M.
BodyLimit int64
// Timeout defines the time after which the context is cancelled and
// processing of the action should be stopped.
//
// Default: 30s.
Timeout time.Duration
// The handler that gets executed with the context.
//
// If returned errors are marked with Safe() they will be included in the
// returned JSON-API error.
Handler Handler
}
// M is a shorthand type to create a map of actions.
type M = map[string]*Action
// A is a shorthand function to construct an action.
func A(name string, methods []string, bodyLimit int64, timeout time.Duration, h Handler) *Action {
// panic if methods or handler is not set
if len(methods) == 0 || h == nil {
panic("fire: missing methods or handler")
}
return &Action{
Methods: methods,
BodyLimit: bodyLimit,
Timeout: timeout,
Handler: func(ctx *Context) error {
// trace
ctx.Tracer.Push(name)
defer ctx.Tracer.Pop()
// call handler
err := h(ctx)
if err != nil {
return xo.W(err)
}
return nil
},
}
}
// Handler is function that takes a context, mutates is to modify the behaviour
// and response or return an error.
type Handler func(ctx *Context) error
// Matcher is a function that makes an assessment of a context and decides whether
// an operation should be allowed to be carried out.
type Matcher func(ctx *Context) bool
// All will match all contexts.
func All() Matcher {
return func(ctx *Context) bool {
return true
}
}
// Only will match if the operation is present in the provided list.
func Only(op Operation) Matcher {
return func(ctx *Context) bool {
return ctx.Operation&op != 0
}
}
// Except will match if the operation is not present in the provided list.
func Except(op Operation) Matcher {
return func(ctx *Context) bool {
return ctx.Operation&op == 0
}
}
// Combine will combine multiple callbacks.
func Combine(name string, stage Stage, cbs ...*Callback) *Callback {
// check stage
if stage != 0 {
for _, cb := range cbs {
if cb.Stage&stage == 0 {
panic("fire: callback does not support stage")
}
}
}
return C(name, stage, func(ctx *Context) bool {
// check if one of the callback matches
for _, cb := range cbs {
if cb.Matcher(ctx) {
return true
}
}
return false
}, func(ctx *Context) error {
// call all matching callbacks
for _, cb := range cbs {
if ctx.Stage&cb.Stage != 0 && cb.Matcher(ctx) {
err := cb.Handler(ctx)
if err != nil {
return xo.W(err)
}
}
}
return nil
})
}