boosty

Форк
0
/
request.go 
134 строки · 3.1 Кб
1
package request
2

3
import (
4
	"encoding/json"
5
	"errors"
6
	"fmt"
7
	"io"
8
	"net/http"
9
	"net/url"
10
	"strings"
11
	"time"
12

13
	"gohome.4gophers.ru/getapp/boosty/auth"
14
)
15

16
type Request struct {
17
	url    string
18
	client *http.Client
19
	auth   *auth.Auth
20
}
21

22
func New(options ...Option) (*Request, error) {
23
	auth, err := auth.New()
24
	if err != nil {
25
		return nil, err
26
	}
27

28
	r := &Request{
29
		url:    "https://api.boosty.to",
30
		client: &http.Client{},
31
		auth:   auth,
32
	}
33

34
	for _, o := range options {
35
		if err := o(r); err != nil {
36
			return nil, err
37
		}
38
	}
39

40
	return r, nil
41
}
42

43
// check auth code and re request
44
func (b *Request) Request(method string, u string, body io.Reader) (*http.Response, error) {
45
	resp, err := b.do(method, b.url+u, body)
46
	if err != nil {
47
		return nil, fmt.Errorf("error on do request: %w", err)
48
	}
49

50
	if resp.StatusCode == http.StatusUnauthorized {
51
		if err := b.refresh(); err != nil {
52
			return nil, fmt.Errorf("error on refresh token: %w", err)
53
		}
54

55
		resp, err = b.do(method, u, body)
56
		if err != nil {
57
			return nil, fmt.Errorf("error on do request: %w", err)
58
		}
59
	}
60

61
	return resp, nil
62
}
63

64
// create request with auth token
65
func (b *Request) do(method string, u string, body io.Reader) (*http.Response, error) {
66
	req, err := http.NewRequest(method, u, body)
67
	if err != nil {
68
		return nil, fmt.Errorf("boosty stats request error: %w", err)
69
	}
70

71
	req.Header.Add("Authorization", b.auth.BearerHeader())
72

73
	resp, err := b.client.Do(req)
74
	if err != nil {
75
		return nil, fmt.Errorf("boosty stats do error: %w", err)
76
	}
77

78
	return resp, nil
79
}
80

81
type Refresh struct {
82
	AccessToken  string `json:"access_token"`
83
	RefreshToken string `json:"refresh_token"`
84
	ExpiresIn    int64  `json:"expires_in"`
85
}
86

87
func (b *Request) refresh() error {
88
	if b.auth.RefreshToken() == "" {
89
		return errors.New("empty refresh token")
90
	}
91

92
	form := url.Values{}
93
	form.Add("device_id", b.auth.DeviceId())
94
	form.Add("device_os", "web")
95
	form.Add("grant_type", "refresh_token")
96
	form.Add("refresh_token", b.auth.RefreshToken())
97

98
	req, err := http.NewRequest(http.MethodPost, b.url+"/oauth/token/", strings.NewReader(form.Encode()))
99
	if err != nil {
100
		return fmt.Errorf("boosty refresh request error: %w", err)
101
	}
102

103
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
104
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36")
105
	req.Header.Set("Authorization", b.auth.BearerHeader())
106
	resp, err := b.client.Do(req)
107
	if err != nil {
108
		return fmt.Errorf("boosty refresh do error: %w", err)
109
	}
110

111
	if resp.StatusCode != http.StatusOK {
112
		return fmt.Errorf("boosty refresh do error: %d", resp.StatusCode)
113
	}
114

115
	refresh := Refresh{}
116

117
	if err := json.NewDecoder(resp.Body).Decode(&refresh); err != nil {
118
		return fmt.Errorf("boosty refresh decode error: %w", err)
119
	}
120

121
	info := auth.Info{
122
		AccessToken:  refresh.AccessToken,
123
		RefreshToken: refresh.RefreshToken,
124
		ExpiresAt:    time.Now().Unix() + refresh.ExpiresIn,
125
		DeviceId:     b.auth.DeviceId(),
126
	}
127

128
	b.auth.Update(info)
129
	if err := b.auth.Save(); err != nil {
130
		return fmt.Errorf("boosty refresh save error: %w", err)
131
	}
132

133
	return nil
134
}
135

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.