-
Notifications
You must be signed in to change notification settings - Fork 0
/
qiwip2p.go
137 lines (114 loc) · 4.29 KB
/
qiwip2p.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
// https://developer.qiwi.com/ru/p2p-payments/
package qiwip2p
import (
"encoding/json"
"errors"
"fmt"
jsoniter "github.com/json-iterator/go"
"github.com/valyala/fasthttp"
)
// Интерфейс для взаимодействия с API P2P-счетов по стандарту OAuth 2.0.
type API struct {
// Публичный ключ для авторизации при выставлении счетов через форму.
PublicKey string
// Секретный ключ для авторизации запросов к API
SecretKey string
// Функция, которая используется для http запросов к Qiwi P2P API
HttpDoRequest func(method string, url string, headers map[string]string, body []byte) (respStatusCode int, respBody []byte, err error)
}
// Создаёт новый интерфейс для взаимодействия с API P2P-счетов Qiwi.
// Если вы хотите кастомизировать выполнение HTTP запросов к API, создавайте объект API самостоятельно,
// в поле HttpDoRequest можно указать свою функцию для выполнения HTTP запросов.
func NewAPI(publicKey string, secretKey string) *API {
return &API{
PublicKey: publicKey,
SecretKey: secretKey,
HttpDoRequest: DefaultHttpDoRequest,
}
}
var defaultFasthttpClient = &fasthttp.Client{
NoDefaultUserAgentHeader: true,
DisableHeaderNamesNormalizing: true,
DisablePathNormalizing: true,
}
func DefaultHttpDoRequest(method string, url string, headers map[string]string, body []byte) (respStatusCode int, respBody []byte, err error) {
req := &fasthttp.Request{}
req.Header.SetMethod(method)
req.SetRequestURI(url)
for k, v := range headers {
req.Header.Set(k, v)
}
req.SetBody(body)
resp := &fasthttp.Response{}
err = defaultFasthttpClient.Do(req, resp)
if err != nil {
return 0, nil, fmt.Errorf("DefaultHttpDoRequest: %w", err)
}
respStatusCode = resp.StatusCode()
respBody = resp.Body()
return
}
func (api *API) makeAPICall(httpMethod string, pathCompound string, billMeta *BillMetadata) (*BillMetadata, error) {
requestURL := "https://api.qiwi.com/partner/bill/v1/bills/" + pathCompound
var body []byte
if billMeta != nil {
jsoniterCfg := jsoniter.Config{
EscapeHTML: false,
OnlyTaggedField: true,
ObjectFieldMustBeSimpleString: true,
CaseSensitive: true,
}.Froze()
var err error
body, err = jsoniterCfg.Marshal(billMeta)
if err != nil {
return nil, fmt.Errorf("makeAPICall: %w", err)
}
}
respStatusCode, respBody, err := api.HttpDoRequest(httpMethod, requestURL, map[string]string{
"Authorization": "Bearer " + api.SecretKey,
"Accept": "application/json",
"Content-Type": "application/json",
}, body)
if err != nil {
return nil, fmt.Errorf("makeAPICall: %w", err)
}
if respStatusCode < 200 || respStatusCode >= 300 {
return nil, fmt.Errorf("makeAPICall: qiwi p2p api error (status code %v): %w", respStatusCode, errors.New(string(respBody)))
}
responseData := &BillMetadata{}
err = json.Unmarshal(respBody, responseData)
if err != nil {
return nil, fmt.Errorf("makeAPICall: %w", err)
}
return responseData, nil
}
// Выставление счета
//
// https://developer.qiwi.com/ru/p2p-payments/#create
func (api *API) CreateBill(billID BillID, billMeta *BillMetadata) (*BillMetadata, error) {
respBillMeta, err := api.makeAPICall("PUT", string(billID), billMeta)
if err != nil {
return nil, fmt.Errorf("CreateBill: %w", err)
}
return respBillMeta, nil
}
// Проверка статуса перевода по счету
//
// https://developer.qiwi.com/ru/p2p-payments/#invoice-status
func (api *API) GetBill(billID BillID) (*BillMetadata, error) {
respBillMeta, err := api.makeAPICall("GET", string(billID), nil)
if err != nil {
return nil, fmt.Errorf("GetBill: %w", err)
}
return respBillMeta, nil
}
// Отмена неоплаченного счета
//
// https://developer.qiwi.com/ru/p2p-payments/#cancel
func (api *API) CancelBill(billID BillID) (*BillMetadata, error) {
respBillMeta, err := api.makeAPICall("POST", string(billID)+"/reject", nil)
if err != nil {
return nil, fmt.Errorf("CancelBill: %w", err)
}
return respBillMeta, nil
}