All checks were successful
Golang test / go-test (push) Successful in 14s
Check the `retry-after` header first for rate limit waits. Fall back to `x-ratelimit-remaining` and `x-ratelimit-reset` if necessary, correctly interpreting the reset value as a Unix timestamp. Also simplifies the `ReRequest` helper to use `http.DefaultClient` and refines panic recovery in Gitea asset uploads.
126 lines
3.6 KiB
Go
126 lines
3.6 KiB
Go
// Client to Github APIs
|
|
package github
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
|
|
"sirherobrine23.com.br/go-bds/request/v2"
|
|
)
|
|
|
|
var (
|
|
GithubAPI = &url.URL{Scheme: "https", Host: "api.github.com", Path: "/"} // Defaut github api
|
|
|
|
ErrToken error = errors.New("require Token to request")
|
|
|
|
err500 = request.RequestStatusFunction(func(res *http.Response) (*http.Response, error) {
|
|
buffLog, _ := io.ReadAll(res.Body)
|
|
if res.Body != nil {
|
|
res.Body.Close()
|
|
}
|
|
if len(buffLog) == 0 {
|
|
buffLog = []byte("not body response")
|
|
}
|
|
return nil, fmt.Errorf("cannot process request (%s), github api is down: %s", res.Request.URL.String(), buffLog)
|
|
})
|
|
|
|
processCodes = request.MapCode{
|
|
500: err500,
|
|
501: err500,
|
|
401: func(res *http.Response) (*http.Response, error) {
|
|
if res.Body != nil {
|
|
res.Body.Close()
|
|
}
|
|
return nil, ErrToken
|
|
},
|
|
403: func(res *http.Response) (*http.Response, error) {
|
|
if res.Body != nil {
|
|
res.Body.Close()
|
|
}
|
|
if retryAfter := res.Header.Get("retry-after"); retryAfter != "" && retryAfter != "0" {
|
|
if dateSec, err := strconv.ParseInt(retryAfter, 10, 64); err == nil {
|
|
<-time.After(time.Unix(dateSec, dateSec*int64(time.Second)).Sub(time.Now()))
|
|
return request.ReRequest(res)
|
|
}
|
|
} else if remining := res.Header.Get("x-ratelimit-remaining"); remining == "0" {
|
|
if reset := res.Header.Get("x-ratelimit-reset"); reset != "" {
|
|
if dateSec, err := strconv.ParseInt(reset, 10, 64); err == nil {
|
|
<-time.After(time.Unix(dateSec, dateSec*int64(time.Second)).Sub(time.Now()))
|
|
return request.ReRequest(res)
|
|
}
|
|
}
|
|
}
|
|
return nil, errors.New("cannot process request, authorization or not have permission")
|
|
},
|
|
429: func(res *http.Response) (*http.Response, error) {
|
|
if res.Body != nil {
|
|
res.Body.Close()
|
|
}
|
|
if retryAfter := res.Header.Get("retry-after"); retryAfter != "" && retryAfter != "0" {
|
|
if dateSec, err := strconv.ParseInt(retryAfter, 10, 64); err == nil {
|
|
<-time.After(time.Unix(dateSec, dateSec*int64(time.Second)).Sub(time.Now()))
|
|
return request.ReRequest(res)
|
|
}
|
|
} else if remining := res.Header.Get("x-ratelimit-remaining"); remining == "0" {
|
|
if reset := res.Header.Get("x-ratelimit-reset"); reset != "" {
|
|
if dateSec, err := strconv.ParseInt(reset, 10, 64); err == nil {
|
|
<-time.After(time.Unix(dateSec, dateSec*int64(time.Second)).Sub(time.Now()))
|
|
return request.ReRequest(res)
|
|
}
|
|
}
|
|
}
|
|
return nil, errors.New("many requests to github api")
|
|
},
|
|
}
|
|
)
|
|
|
|
// Create new Github Client with Github.com API host
|
|
func NewClient(Username, Repository, Token string) *Github {
|
|
return &Github{
|
|
Host: GithubAPI,
|
|
Repository: Repository,
|
|
Username: Username,
|
|
Token: Token,
|
|
}
|
|
}
|
|
|
|
// Create new Github Client
|
|
func NewClientHost(apiHost, Username, Repository, Token string) (*Github, error) {
|
|
hostUrl, err := url.Parse(apiHost)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Github{
|
|
Host: hostUrl,
|
|
Repository: Repository,
|
|
Username: Username,
|
|
Token: Token,
|
|
}, nil
|
|
}
|
|
|
|
// Basic client to Github APIs
|
|
type Github struct {
|
|
Host *url.URL // Github API host
|
|
Token string // Github Token
|
|
|
|
// User and Repository name
|
|
Username, Repository string
|
|
}
|
|
|
|
// Return escapated Owner+/+Repository
|
|
func (client Github) repoPath() string {
|
|
return fmt.Sprintf("%s/%s", url.PathEscape(client.Username), url.PathEscape(client.Repository))
|
|
}
|
|
|
|
// Set token to header
|
|
func (client Github) authHeader(header *request.Header) {
|
|
if client.Token != "" {
|
|
(*header)["Authorization"] = fmt.Sprintf("Bearer %s", client.Token)
|
|
}
|
|
}
|