William Kurkian | ea86948 | 2019-04-09 15:16:11 -0400 | [diff] [blame] | 1 | package api |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "strconv" |
| 6 | ) |
| 7 | |
| 8 | // Event can be used to query the Event endpoints |
| 9 | type Event struct { |
| 10 | c *Client |
| 11 | } |
| 12 | |
| 13 | // UserEvent represents an event that was fired by the user |
| 14 | type UserEvent struct { |
| 15 | ID string |
| 16 | Name string |
| 17 | Payload []byte |
| 18 | NodeFilter string |
| 19 | ServiceFilter string |
| 20 | TagFilter string |
| 21 | Version int |
| 22 | LTime uint64 |
| 23 | } |
| 24 | |
| 25 | // Event returns a handle to the event endpoints |
| 26 | func (c *Client) Event() *Event { |
| 27 | return &Event{c} |
| 28 | } |
| 29 | |
| 30 | // Fire is used to fire a new user event. Only the Name, Payload and Filters |
| 31 | // are respected. This returns the ID or an associated error. Cross DC requests |
| 32 | // are supported. |
| 33 | func (e *Event) Fire(params *UserEvent, q *WriteOptions) (string, *WriteMeta, error) { |
| 34 | r := e.c.newRequest("PUT", "/v1/event/fire/"+params.Name) |
| 35 | r.setWriteOptions(q) |
| 36 | if params.NodeFilter != "" { |
| 37 | r.params.Set("node", params.NodeFilter) |
| 38 | } |
| 39 | if params.ServiceFilter != "" { |
| 40 | r.params.Set("service", params.ServiceFilter) |
| 41 | } |
| 42 | if params.TagFilter != "" { |
| 43 | r.params.Set("tag", params.TagFilter) |
| 44 | } |
| 45 | if params.Payload != nil { |
| 46 | r.body = bytes.NewReader(params.Payload) |
| 47 | } |
| 48 | |
| 49 | rtt, resp, err := requireOK(e.c.doRequest(r)) |
| 50 | if err != nil { |
| 51 | return "", nil, err |
| 52 | } |
| 53 | defer resp.Body.Close() |
| 54 | |
| 55 | wm := &WriteMeta{RequestTime: rtt} |
| 56 | var out UserEvent |
| 57 | if err := decodeBody(resp, &out); err != nil { |
| 58 | return "", nil, err |
| 59 | } |
| 60 | return out.ID, wm, nil |
| 61 | } |
| 62 | |
| 63 | // List is used to get the most recent events an agent has received. |
| 64 | // This list can be optionally filtered by the name. This endpoint supports |
| 65 | // quasi-blocking queries. The index is not monotonic, nor does it provide provide |
| 66 | // LastContact or KnownLeader. |
| 67 | func (e *Event) List(name string, q *QueryOptions) ([]*UserEvent, *QueryMeta, error) { |
| 68 | r := e.c.newRequest("GET", "/v1/event/list") |
| 69 | r.setQueryOptions(q) |
| 70 | if name != "" { |
| 71 | r.params.Set("name", name) |
| 72 | } |
| 73 | rtt, resp, err := requireOK(e.c.doRequest(r)) |
| 74 | if err != nil { |
| 75 | return nil, nil, err |
| 76 | } |
| 77 | defer resp.Body.Close() |
| 78 | |
| 79 | qm := &QueryMeta{} |
| 80 | parseQueryMeta(resp, qm) |
| 81 | qm.RequestTime = rtt |
| 82 | |
| 83 | var entries []*UserEvent |
| 84 | if err := decodeBody(resp, &entries); err != nil { |
| 85 | return nil, nil, err |
| 86 | } |
| 87 | return entries, qm, nil |
| 88 | } |
| 89 | |
| 90 | // IDToIndex is a bit of a hack. This simulates the index generation to |
| 91 | // convert an event ID into a WaitIndex. |
| 92 | func (e *Event) IDToIndex(uuid string) uint64 { |
| 93 | lower := uuid[0:8] + uuid[9:13] + uuid[14:18] |
| 94 | upper := uuid[19:23] + uuid[24:36] |
| 95 | lowVal, err := strconv.ParseUint(lower, 16, 64) |
| 96 | if err != nil { |
| 97 | panic("Failed to convert " + lower) |
| 98 | } |
| 99 | highVal, err := strconv.ParseUint(upper, 16, 64) |
| 100 | if err != nil { |
| 101 | panic("Failed to convert " + upper) |
| 102 | } |
| 103 | return lowVal ^ highVal |
| 104 | } |