131 lines
4.4 KiB
Go
131 lines
4.4 KiB
Go
|
package mailgun
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"github.com/mbanzon/simplehttp"
|
||
|
"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 := simplehttp.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 := simplehttp.NewHTTPRequest(url)
|
||
|
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
|
||
|
}
|