-
Notifications
You must be signed in to change notification settings - Fork 0
/
request.go
130 lines (115 loc) · 3.19 KB
/
request.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
package acomm
import (
"encoding/json"
"errors"
"net/url"
"time"
log "github.com/Sirupsen/logrus"
"github.com/pborman/uuid"
)
// Request is a request data structure for asynchronous requests. The ID is
// used to identify the request throught its life cycle. The ResponseHook is a
// URL where response data should be sent. SuccessHandler and ErrorHandler will
// be called appropriately to handle a response.
type Request struct {
ID string `json:"id"`
Task string `json:"task"`
ResponseHook *url.URL `json:"responsehook"`
Args *json.RawMessage `json:"args"`
SuccessHandler ResponseHandler `json:"-"`
ErrorHandler ResponseHandler `json:"-"`
timeout *time.Timer
proxied bool
}
// ResponseHandler is a function to run when a request receives a response.
type ResponseHandler func(*Request, *Response)
// NewRequest creates a new Request instance.
func NewRequest(task, responseHook string, args interface{}, sh ResponseHandler, eh ResponseHandler) (*Request, error) {
hook, err := url.ParseRequestURI(responseHook)
if err != nil {
log.WithFields(log.Fields{
"error": err,
"responseHook": responseHook,
}).Error("invalid response hook url")
return nil, err
}
if task == "" {
return nil, errors.New("missing task")
}
argsJSON, err := json.Marshal(args)
if err != nil {
return nil, err
}
return &Request{
ID: uuid.New(),
Task: task,
ResponseHook: hook,
Args: (*json.RawMessage)(&argsJSON),
SuccessHandler: sh,
ErrorHandler: eh,
}, nil
}
// UnmarshalArgs unmarshals the request args into the destination object.
func (req *Request) UnmarshalArgs(dest interface{}) error {
return unmarshalFromRaw(req.Args, dest)
}
func unmarshalFromRaw(src *json.RawMessage, dest interface{}) error {
if src == nil {
return nil
}
err := json.Unmarshal(*src, dest)
if err != nil {
log.WithFields(log.Fields{
"error": err,
"data": src,
}).Error("failed to unmarshal data")
}
return err
}
// Validate validates the reqeust
func (req *Request) Validate() error {
if req.ID == "" {
err := errors.New("missing id")
log.WithFields(log.Fields{
"req": req,
"error": err,
}).Error("invalid req")
return err
}
if req.Task == "" {
err := errors.New("missing task")
log.WithFields(log.Fields{
"req": req,
"error": err,
}).Error("invalid req")
return err
}
if req.ResponseHook == nil {
err := errors.New("missing response hook")
log.WithFields(log.Fields{
"req": req,
"error": err,
}).Error("invalid req")
return err
}
return nil
}
// Respond sends a Response to a Request's ResponseHook.
func (req *Request) Respond(resp *Response) error {
return Send(req.ResponseHook, resp)
}
// HandleResponse determines whether a response indicates success or error and
// runs the appropriate handler. If the appropriate handler is not defined, it
// is assumed no handling is necessary and silently finishes.
func (req *Request) HandleResponse(resp *Response) {
if resp.Error != nil {
if req.ErrorHandler != nil {
req.ErrorHandler(req, resp)
}
return
}
if req.SuccessHandler != nil {
req.SuccessHandler(req, resp)
return
}
}