forked from milosgajdos/go-playht
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lease.go
107 lines (94 loc) · 2.77 KB
/
lease.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
package playht
import (
"bytes"
"context"
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"time"
"github.com/milosgajdos/go-playht/request"
)
const (
// HTEpoch is the HT Lease epoch.
// I've no idea why but whatever.
HTEpoch int64 = 1519257480 // 2018-02-21 23:58:00 UTC
)
// Lease for gRPC stream.
type Lease struct {
Data []byte
Created time.Time
Duration time.Duration
Metadata map[string]any
}
// Expires returns a timestamp when the Lease expires
func (l *Lease) Expires() time.Time {
return l.Created.Add(l.Duration)
}
// CreateLeaseReq is used to create a nw Lease.
type CreateLeaseReq struct{}
// CreateLease creates a new lease and returns it.
func (c *Client) CreateLease(ctx context.Context, _ *CreateLeaseReq) (*Lease, error) {
u, err := url.Parse(c.opts.BaseURL + "/" + c.opts.Version + "/leases")
if err != nil {
return nil, err
}
options := []request.HTTPOption{
request.WithBearer(c.opts.SecretKey),
request.WithSetHeader(UserIDHeader, c.opts.UserID),
request.WithAddHeader("Accept", "application/json"),
request.WithSetHeader("Content-Type", "application/json"),
}
req, err := request.NewHTTP(ctx, http.MethodPost, u.String(), nil, options...)
if err != nil {
return nil, err
}
resp, err := request.Do[APIErrGen](c.opts.HTTPClient, req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
switch resp.StatusCode {
case http.StatusCreated:
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var created, duration int32
buf := bytes.NewReader(data[64:68])
if err := binary.Read(buf, binary.BigEndian, &created); err != nil {
return nil, fmt.Errorf("failed reading created data: %v", err)
}
buf = bytes.NewReader(data[68:72])
if err := binary.Read(buf, binary.BigEndian, &duration); err != nil {
return nil, fmt.Errorf("failed reading duration data: %v", err)
}
md := map[string]any{}
if err := json.Unmarshal(data[72:], &md); err != nil {
return nil, fmt.Errorf("failed reading lease metadata: %v", err)
}
return &Lease{
Data: data,
Created: time.Unix(HTEpoch, 0).Add(time.Duration(created) * time.Second),
Duration: time.Duration(duration) * time.Second,
Metadata: md,
}, nil
case http.StatusTooManyRequests:
return nil, ErrTooManyRequests
case http.StatusInternalServerError:
var apiErr APIErrInternal
if jsonErr := json.NewDecoder(resp.Body).Decode(&apiErr); jsonErr != nil {
return nil, errors.Join(err, jsonErr)
}
return nil, apiErr
default:
return nil, fmt.Errorf("%w: %d", ErrUnexpectedStatusCode, resp.StatusCode)
}
}
// RefreshLease refreshes the existing Lease and returns it.
func (c *Client) RefreshLease(ctx context.Context, createReq *CreateLeaseReq) (*Lease, error) {
return c.CreateLease(ctx, createReq)
}