1package crr
2
3import (
4	"net/url"
5	"sort"
6	"strings"
7	"time"
8
9	"github.com/aws/aws-sdk-go/aws"
10)
11
12// Endpoint represents an endpoint used in endpoint discovery.
13type Endpoint struct {
14	Key       string
15	Addresses WeightedAddresses
16}
17
18// WeightedAddresses represents a list of WeightedAddress.
19type WeightedAddresses []WeightedAddress
20
21// WeightedAddress represents an address with a given weight.
22type WeightedAddress struct {
23	URL     *url.URL
24	Expired time.Time
25}
26
27// HasExpired will return whether or not the endpoint has expired with
28// the exception of a zero expiry meaning does not expire.
29func (e WeightedAddress) HasExpired() bool {
30	return e.Expired.Before(time.Now())
31}
32
33// Add will add a given WeightedAddress to the address list of Endpoint.
34func (e *Endpoint) Add(addr WeightedAddress) {
35	e.Addresses = append(e.Addresses, addr)
36}
37
38// Len returns the number of valid endpoints where valid means the endpoint
39// has not expired.
40func (e *Endpoint) Len() int {
41	validEndpoints := 0
42	for _, endpoint := range e.Addresses {
43		if endpoint.HasExpired() {
44			continue
45		}
46
47		validEndpoints++
48	}
49	return validEndpoints
50}
51
52// GetValidAddress will return a non-expired weight endpoint
53func (e *Endpoint) GetValidAddress() (WeightedAddress, bool) {
54	for i := 0; i < len(e.Addresses); i++ {
55		we := e.Addresses[i]
56
57		if we.HasExpired() {
58			e.Addresses = append(e.Addresses[:i], e.Addresses[i+1:]...)
59			i--
60			continue
61		}
62
63		return we, true
64	}
65
66	return WeightedAddress{}, false
67}
68
69// Discoverer is an interface used to discovery which endpoint hit. This
70// allows for specifics about what parameters need to be used to be contained
71// in the Discoverer implementor.
72type Discoverer interface {
73	Discover() (Endpoint, error)
74}
75
76// BuildEndpointKey will sort the keys in alphabetical order and then retrieve
77// the values in that order. Those values are then concatenated together to form
78// the endpoint key.
79func BuildEndpointKey(params map[string]*string) string {
80	keys := make([]string, len(params))
81	i := 0
82
83	for k := range params {
84		keys[i] = k
85		i++
86	}
87	sort.Strings(keys)
88
89	values := make([]string, len(params))
90	for i, k := range keys {
91		if params[k] == nil {
92			continue
93		}
94
95		values[i] = aws.StringValue(params[k])
96	}
97
98	return strings.Join(values, ".")
99}
100