forked from glycerine/sshego
-
Notifications
You must be signed in to change notification settings - Fork 0
/
events.go
130 lines (115 loc) · 4.35 KB
/
events.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 mailgun
import (
"fmt"
"time"
)
// Events are open-ended, loosely-defined JSON documents.
// They will always have an event and a timestamp field, however.
type Event map[string]interface{}
// noTime always equals an uninitialized Time structure.
// It's used to detect when a time parameter is provided.
var noTime time.Time
// GetEventsOptions lets the caller of GetEvents() specify how the results are to be returned.
// Begin and End time-box the results returned.
// ForceAscending and ForceDescending are used to force Mailgun to use a given traversal order of the events.
// If both ForceAscending and ForceDescending are true, an error will result.
// If none, the default will be inferred from the Begin and End parameters.
// Limit caps the number of results returned. If left unspecified, Mailgun assumes 100.
// Compact, if true, compacts the returned JSON to minimize transmission bandwidth.
// Otherwise, the JSON is spaced appropriately for human consumption.
// Filter allows the caller to provide more specialized filters on the query.
// Consult the Mailgun documentation for more details.
type GetEventsOptions struct {
Begin, End time.Time
ForceAscending, ForceDescending, Compact bool
Limit int
Filter map[string]string
}
// EventIterator maintains the state necessary for paging though small parcels of a larger set of events.
type EventIterator struct {
events []Event
nextURL, prevURL string
mg Mailgun
}
// NewEventIterator creates a new iterator for events.
// Use GetFirstPage to retrieve the first batch of events.
// Use Next and Previous thereafter as appropriate to iterate through sets of data.
func (mg *MailgunImpl) NewEventIterator() *EventIterator {
return &EventIterator{mg: mg}
}
// Events returns the most recently retrieved batch of events.
// The length is guaranteed to fall between 0 and the limit set in the GetEventsOptions structure passed to GetFirstPage.
func (ei *EventIterator) Events() []Event {
return ei.events
}
// GetFirstPage retrieves the first batch of events, according to your criteria.
// See the GetEventsOptions structure for more details on how the fields affect the data returned.
func (ei *EventIterator) GetFirstPage(opts GetEventsOptions) error {
if opts.ForceAscending && opts.ForceDescending {
return fmt.Errorf("collation cannot at once be both ascending and descending")
}
payload := newUrlEncodedPayload()
if opts.Limit != 0 {
payload.addValue("limit", fmt.Sprintf("%d", opts.Limit))
}
if opts.Compact {
payload.addValue("pretty", "no")
}
if opts.ForceAscending {
payload.addValue("ascending", "yes")
}
if opts.ForceDescending {
payload.addValue("ascending", "no")
}
if opts.Begin != noTime {
payload.addValue("begin", formatMailgunTime(&opts.Begin))
}
if opts.End != noTime {
payload.addValue("end", formatMailgunTime(&opts.End))
}
if opts.Filter != nil {
for k, v := range opts.Filter {
payload.addValue(k, v)
}
}
url, err := generateParameterizedUrl(ei.mg, eventsEndpoint, payload)
if err != nil {
return err
}
return ei.fetch(url)
}
// Retrieves the chronologically previous batch of events, if any exist.
// You know you're at the end of the list when len(Events())==0.
func (ei *EventIterator) GetPrevious() error {
return ei.fetch(ei.prevURL)
}
// Retrieves the chronologically next batch of events, if any exist.
// You know you're at the end of the list when len(Events())==0.
func (ei *EventIterator) GetNext() error {
return ei.fetch(ei.nextURL)
}
// GetFirstPage, GetPrevious, and GetNext all have a common body of code.
// fetch completes the API fetch common to all three of these functions.
func (ei *EventIterator) fetch(url string) error {
r := newHTTPRequest(url)
r.setClient(ei.mg.Client())
r.setBasicAuth(basicAuthUser, ei.mg.ApiKey())
var response map[string]interface{}
err := getResponseFromJSON(r, &response)
if err != nil {
return err
}
items := response["items"].([]interface{})
ei.events = make([]Event, len(items))
for i, item := range items {
ei.events[i] = item.(map[string]interface{})
}
pagings := response["paging"].(map[string]interface{})
links := make(map[string]string, len(pagings))
for key, page := range pagings {
links[key] = page.(string)
}
ei.nextURL = links["next"]
ei.prevURL = links["previous"]
return err
}