// Client to Github APIs package github import ( "errors" "fmt" "io" "net/http" "net/url" "strconv" "time" "sirherobrine23.com.br/go-bds/request/v3" ) var ( GithubAPI = &url.URL{Scheme: "https", Host: "api.github.com", Path: "/"} // Defaut github api ErrToken error = errors.New("require Token to request") err500 = request.ProcessRequest(func(req *request.RequestStatus) (res *http.Response, err error) { buffLog, _ := io.ReadAll(req.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.CodeProcess{ 500: err500, 501: err500, 401: func(req *request.RequestStatus) (res *http.Response, err error) { if res.Body != nil { res.Body.Close() } return nil, ErrToken }, 403: func(req *request.RequestStatus) (res *http.Response, err 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.Until(time.Unix(dateSec, dateSec*int64(time.Second)))) return request.Request(req.URL, req.Options) } } 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.Until(time.Unix(dateSec, dateSec*int64(time.Second)))) return request.Request(req.URL, req.Options) } } } return nil, errors.New("cannot process request, authorization or not have permission") }, 429: func(req *request.RequestStatus) (res *http.Response, err 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.Until(time.Unix(dateSec, dateSec*int64(time.Second)))) return request.Request(req.URL, req.Options) } } 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.Until(time.Unix(dateSec, dateSec*int64(time.Second)))) return request.Request(req.URL, req.Options) } } } 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 *http.Header) { if client.Token != "" { (*header)["Authorization"] = []string{fmt.Sprintf("Bearer %s", client.Token)} } }