-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhandle.go
153 lines (127 loc) · 3.79 KB
/
handle.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package easierweb
import (
"errors"
"github.com/julienschmidt/httprouter"
"golang.org/x/net/websocket"
"net/http"
"reflect"
)
type Handle func(ctx *Context)
type RequestHandle func(ctx *Context, reqObj any) error
type ResponseHandle func(ctx *Context, result any, err error)
type ErrorHandle func(ctx *Context, err any)
func (r *Router) handle(route string, handle Handle, res http.ResponseWriter, req *http.Request, par httprouter.Params, ws *websocket.Conn, sse bool, middlewares ...Handle) {
ctx := r.contextPool.Get().(*Context)
err := setContext(ctx, r, route, res, req, par, ws, middlewares...)
defer func() {
if ctx != nil {
r.contextPool.Put(ctx)
}
sErr := recover()
if sErr != nil && r.errorHandle != nil {
r.errorBottomUp(ctx, sErr)
}
}()
if err != nil {
panic(err)
}
if sse {
res.Header().Set("Content-Type", "text/event-stream")
res.Header().Set("Cache-Control", "no-cache")
res.Header().Set("Connection", "keep-alive")
res.Header().Set("Access-Control-Allow-Origin", "*")
flusher, ok := res.(http.Flusher)
if !ok {
panic(errors.New("client does not support server-sent events"))
}
ctx.Flusher = flusher
}
// middleware execution
ctx.handles = append(ctx.handles, handle)
for ctx.index < len(ctx.handles) {
ctx.handles[ctx.index](ctx)
ctx.index++
}
// if a websocket connection exists, the websocket connection is automatically closed when the function returns
if ws != nil {
err = ctx.Close()
if err != nil {
panic(err)
}
}
}
func (r *Router) easyHandle(easyHandle any) Handle {
return func(ctx *Context) {
// verify
if r.requestHandle == nil {
panic(errors.New("request handle is empty"))
}
if r.responseHandle == nil {
panic(errors.New("response handle is empty"))
}
// reflection gets the type of function
funcType := reflect.TypeOf(easyHandle)
// create a slice of the parameter value
var paramValues []reflect.Value
var reqObj any = nil
// if there is no second parameter, there is no auto-binding
if funcType.NumIn() == 1 {
paramValues = make([]reflect.Value, 1)
paramValues[0] = reflect.ValueOf(ctx).Elem().Addr()
} else if funcType.NumIn() == 2 {
paramValues = make([]reflect.Value, 2)
paramValues[0] = reflect.ValueOf(ctx).Elem().Addr()
paramValues[1] = reflect.New(funcType.In(1)).Elem()
reqObj = paramValues[1].Addr().Interface()
} else {
panic(errors.New("handle input parameters does not match"))
}
if reqObj != nil {
err := r.requestHandle(ctx, reqObj)
if err != nil {
r.responseHandle(ctx, nil, err)
}
}
// call the function
returnValues := reflect.ValueOf(easyHandle).Call(paramValues)
// no object return, no error return
if len(returnValues) == 0 {
r.responseHandle(ctx, nil, nil)
return
}
if len(returnValues) > 2 {
panic(errors.New("handle return values does not match"))
}
// if just one value return
if len(returnValues) == 1 {
firstValue, isErr := returnValues[0].Interface().(error)
// if first return value is error
if isErr {
// return error
r.responseHandle(ctx, nil, firstValue)
return
}
}
// get the result value
var resultValue any = nil
if returnValues[0].IsValid() && returnValues[0].Kind() == reflect.Ptr && returnValues[0].Elem().IsValid() {
resultValue = returnValues[0].Elem().Interface()
} else if returnValues[0].IsValid() && returnValues[0].Kind() == reflect.Slice {
resultValue = returnValues[0].Interface()
}
// just result return
if len(returnValues) == 1 {
r.responseHandle(ctx, resultValue, nil)
return
}
// has result return and error return
errValue, _ := returnValues[1].Interface().(error)
r.responseHandle(ctx, resultValue, errValue)
}
}
func (r *Router) errorBottomUp(ctx *Context, err any) {
defer func() {
_ = recover()
}()
r.errorHandle(ctx, err)
}