-
Notifications
You must be signed in to change notification settings - Fork 1
/
egvs.go
166 lines (135 loc) · 3.85 KB
/
egvs.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package dexcomClient
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"math"
"net/http"
"sort"
"strconv"
"time"
)
const egvUrl = "/v1/users/self/egvs"
const dateTimeString = "2006-01-02T15:04:05"
type EGVResponse struct {
Unit string `json:"unit"`
Rate string `json:"rate"`
index int
EGVS []*EGV `json:"egvs"`
}
type EGV struct {
SystemTime string
DisplayTime string
Value uint64
Status string
Trend string
TrendRate float64
}
type Range struct {
StartDate string
EndDate string
}
func (client *DexcomClient) GetEGVs(startDate string, endDate string) ([]*EGVResponse, error) {
ranges := getEGVRanges(startDate, endDate)
// egv channel to allow for concurrency in the requests
egvChan := make(chan *EGVResponse)
// err chan just in case there are errors
errChan := make(chan error)
for i, r := range ranges {
go client.getRange(rangeRequest{Range: r, index: i}, egvChan, errChan)
}
var responses []*EGVResponse
// catch all of the requests. There should only be
// len(ranges) so we can just wait for all of those
// to finish
for i, j := 0, len(ranges); i < j; i++ {
select {
case response := <-egvChan:
responses = append(responses, response)
case reqErr := <-errChan:
return nil, reqErr
}
}
sort.Slice(responses, func(i, j int) bool {
return responses[i].index < responses[j].index
})
var egvResponses []*EGVResponse
for _, response := range responses {
egvResponses = append(egvResponses, response)
}
return egvResponses, nil
}
func (client *DexcomClient) getRange(request rangeRequest, resultChan chan *EGVResponse, errChan chan error) {
// Make request with url date range
req, _ := http.NewRequest("GET",
urlWithDateRange(client.config, egvUrl, request.StartDate, request.EndDate), nil)
client.Debug("URL: " + urlWithDateRange(client.config, egvUrl, request.StartDate, request.EndDate))
token, err := client.GetOauthToken()
if err != nil {
errChan <- err
return
}
req.Header.Add("Authorization", "Bearer "+token.AccessToken)
resp, err := http.DefaultClient.Do(req)
if err != nil {
errChan <- err
panic(err)
return
}
body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
fmt.Println(string(body))
panic(errors.New("Code " + strconv.FormatInt(int64(resp.StatusCode), 10)))
}
var jsonResponse EGVResponse
jsonErr := json.Unmarshal(body, &jsonResponse)
// deal with json parse error
if jsonErr != nil {
errChan <- jsonErr
panic(jsonErr)
return
}
jsonResponse.index = request.index
resultChan <- &jsonResponse
}
type rangeRequest struct {
*Range
index int
}
// turns days into nanoseconds
func daysDuration(days int) time.Duration {
return time.Duration(days) * 24 * time.Hour
}
// Get ranges inclusively given a start and end date
func getEGVRanges(start string, end string) []*Range {
// Parse dates
startDate, _ := time.Parse(dateTimeString, start)
endDate, _ := time.Parse(dateTimeString, end)
endUTC := endDate.UTC()
// Get diff between the dates in days
diff := endUTC.Sub(startDate)
daysDiff := diff.Hours() / 24
// Figure out how many months we have to request
// and subtract one because it may not be completely even
monthDistance := int(math.Floor(daysDiff / 90))
var ranges []*Range
for i := 0; i <= monthDistance; i++ {
var requestEndDay time.Time
// Start date is 90 * 2i
requestStartDay := startDate.Add(daysDuration(90*i + i))
if i == monthDistance {
// If we are at the end of the list,
// don't use the diff formula because then we could
// be going over the end date
requestEndDay = endDate
} else {
// End date is (90 * 2i) + 90
// so that we are 90 days ahead of the start date
requestEndDay = startDate.Add(daysDuration((90*i + i) + 90))
}
ranges = append(ranges,
&Range{StartDate: requestStartDay.Format(dateTimeString), EndDate: requestEndDay.Format(dateTimeString)})
}
return ranges
}