1package api
2
3import (
4	"bytes"
5	"strconv"
6)
7
8// Event can be used to query the Event endpoints
9type Event struct {
10	c *Client
11}
12
13// UserEvent represents an event that was fired by the user
14type 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
26func (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.
33func (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	r.header.Set("Content-Type", "application/octet-stream")
49
50	rtt, resp, err := requireOK(e.c.doRequest(r))
51	if err != nil {
52		return "", nil, err
53	}
54	defer closeResponseBody(resp)
55
56	wm := &WriteMeta{RequestTime: rtt}
57	var out UserEvent
58	if err := decodeBody(resp, &out); err != nil {
59		return "", nil, err
60	}
61	return out.ID, wm, nil
62}
63
64// List is used to get the most recent events an agent has received.
65// This list can be optionally filtered by the name. This endpoint supports
66// quasi-blocking queries. The index is not monotonic, nor does it provide provide
67// LastContact or KnownLeader.
68func (e *Event) List(name string, q *QueryOptions) ([]*UserEvent, *QueryMeta, error) {
69	r := e.c.newRequest("GET", "/v1/event/list")
70	r.setQueryOptions(q)
71	if name != "" {
72		r.params.Set("name", name)
73	}
74	rtt, resp, err := requireOK(e.c.doRequest(r))
75	if err != nil {
76		return nil, nil, err
77	}
78	defer closeResponseBody(resp)
79
80	qm := &QueryMeta{}
81	parseQueryMeta(resp, qm)
82	qm.RequestTime = rtt
83
84	var entries []*UserEvent
85	if err := decodeBody(resp, &entries); err != nil {
86		return nil, nil, err
87	}
88	return entries, qm, nil
89}
90
91// IDToIndex is a bit of a hack. This simulates the index generation to
92// convert an event ID into a WaitIndex.
93func (e *Event) IDToIndex(uuid string) uint64 {
94	lower := uuid[0:8] + uuid[9:13] + uuid[14:18]
95	upper := uuid[19:23] + uuid[24:36]
96	lowVal, err := strconv.ParseUint(lower, 16, 64)
97	if err != nil {
98		panic("Failed to convert " + lower)
99	}
100	highVal, err := strconv.ParseUint(upper, 16, 64)
101	if err != nil {
102		panic("Failed to convert " + upper)
103	}
104	return lowVal ^ highVal
105}
106