144 lines
3.2 KiB
Go
144 lines
3.2 KiB
Go
package api
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
|
|
"go.xsfx.dev/glucose_exporter/internal/epoch"
|
|
)
|
|
|
|
const BaseURL = "https://api.libreview.io/llu"
|
|
|
|
// client is our default HTTP client to use.
|
|
//
|
|
//nolint:gochecknoglobals
|
|
var client = http.Client{
|
|
Timeout: 2 * time.Second,
|
|
}
|
|
|
|
func request(
|
|
ctx context.Context,
|
|
method string,
|
|
url string,
|
|
token string,
|
|
data []byte,
|
|
) (*http.Response, error) {
|
|
req, err := http.NewRequest(method, url, bytes.NewReader(data))
|
|
if err != nil {
|
|
return &http.Response{}, fmt.Errorf("creating request: %w", err)
|
|
}
|
|
|
|
req.Header.Add("cache-control", "no-cache")
|
|
req.Header.Add("connection", "Keep-Alive")
|
|
req.Header.Add("content-type", "application/json")
|
|
req.Header.Add("product", "llu.android")
|
|
req.Header.Add("version", "4.7")
|
|
|
|
if token != "" {
|
|
req.Header.Add("authorization", "Bearer "+token)
|
|
}
|
|
|
|
resp, err := client.Do(req.WithContext(ctx))
|
|
if err != nil {
|
|
return &http.Response{}, fmt.Errorf("doing the request: %w", err)
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
type Ticket struct {
|
|
Token string `json:"token"`
|
|
Expires epoch.Epoch `json:"expires"`
|
|
}
|
|
|
|
type LoginResponse struct {
|
|
Data struct {
|
|
AuthTicket Ticket `json:"authTicket"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
func Login(ctx context.Context, baseURL, username, password string) (LoginResponse, error) {
|
|
data := struct {
|
|
Email string `json:"email"`
|
|
Password string `json:"password"`
|
|
}{username, password}
|
|
|
|
d, err := json.Marshal(data)
|
|
if err != nil {
|
|
return LoginResponse{}, fmt.Errorf("marshalling data: %w", err)
|
|
}
|
|
|
|
url, err := url.JoinPath(baseURL, "/auth/login")
|
|
if err != nil {
|
|
return LoginResponse{}, fmt.Errorf("joining url: %w", err)
|
|
}
|
|
|
|
resp, err := request(ctx, http.MethodPost, url, "", d)
|
|
if err != nil {
|
|
return LoginResponse{}, fmt.Errorf("doing request: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return LoginResponse{}, fmt.Errorf("reading body: %w", err)
|
|
}
|
|
|
|
var authTicket LoginResponse
|
|
if err := json.Unmarshal(body, &authTicket); err != nil {
|
|
return LoginResponse{}, fmt.Errorf("unmarshal login response: %w", err)
|
|
}
|
|
|
|
return authTicket, nil
|
|
}
|
|
|
|
type ConnectionsResponse struct {
|
|
Data []struct {
|
|
PatientID string `json:"patientID"`
|
|
|
|
Sensor struct {
|
|
DeviceID string `json:"deviceId"`
|
|
Serialnumber string `json:"sn"`
|
|
} `json:"sensor"`
|
|
|
|
GlucoseMeasurement struct {
|
|
ValueInMgPerDl int `json:"ValueInMgPerDl"`
|
|
TrendArrow int `json:"TrendArrow"`
|
|
} `json:"glucoseMeasurement"`
|
|
} `json:"data"`
|
|
|
|
Ticket Ticket `json:"ticket"`
|
|
}
|
|
|
|
func Connections(ctx context.Context, baseURL, token string) (ConnectionsResponse, error) {
|
|
url, err := url.JoinPath(baseURL, "/connections")
|
|
if err != nil {
|
|
return ConnectionsResponse{}, fmt.Errorf("joining url: %w", err)
|
|
}
|
|
|
|
resp, err := request(ctx, http.MethodGet, url, token, []byte{})
|
|
if err != nil {
|
|
return ConnectionsResponse{}, fmt.Errorf("doing request: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return ConnectionsResponse{}, fmt.Errorf("reading body: %w", err)
|
|
}
|
|
|
|
var connResp ConnectionsResponse
|
|
|
|
if err := json.Unmarshal(body, &connResp); err != nil {
|
|
return ConnectionsResponse{}, fmt.Errorf("unmarshal response: %w", err)
|
|
}
|
|
|
|
return connResp, nil
|
|
}
|