forked from TrueCloudLab/rclone
vendor: add github.com/putdotio/go-putio for putio client
This commit is contained in:
parent
8159658e67
commit
566aa0fca7
15 changed files with 1315 additions and 0 deletions
180
vendor/github.com/putdotio/go-putio/putio/client.go
generated
vendored
Normal file
180
vendor/github.com/putdotio/go-putio/putio/client.go
generated
vendored
Normal file
|
@ -0,0 +1,180 @@
|
|||
package putio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultUserAgent = "go-putio"
|
||||
defaultMediaType = "application/json"
|
||||
defaultBaseURL = "https://api.put.io"
|
||||
defaultUploadURL = "https://upload.put.io"
|
||||
)
|
||||
|
||||
// Client manages communication with Put.io v2 API.
|
||||
type Client struct {
|
||||
// HTTP client used to communicate with Put.io API
|
||||
client *http.Client
|
||||
|
||||
// Base URL for API requests
|
||||
BaseURL *url.URL
|
||||
|
||||
// base url for upload requests
|
||||
uploadURL *url.URL
|
||||
|
||||
// User agent for client
|
||||
UserAgent string
|
||||
|
||||
// ExtraHeaders are passed to the API server on every request.
|
||||
ExtraHeaders http.Header
|
||||
|
||||
// Services used for communicating with the API
|
||||
Account *AccountService
|
||||
Files *FilesService
|
||||
Transfers *TransfersService
|
||||
Zips *ZipsService
|
||||
Friends *FriendsService
|
||||
Events *EventsService
|
||||
}
|
||||
|
||||
// NewClient returns a new Put.io API client, using the htttpClient, which must
|
||||
// be a new Oauth2 enabled http.Client. If httpClient is not defined, default
|
||||
// HTTP client is used.
|
||||
func NewClient(httpClient *http.Client) *Client {
|
||||
if httpClient == nil {
|
||||
httpClient = http.DefaultClient
|
||||
}
|
||||
|
||||
baseURL, _ := url.Parse(defaultBaseURL)
|
||||
uploadURL, _ := url.Parse(defaultUploadURL)
|
||||
c := &Client{
|
||||
client: httpClient,
|
||||
BaseURL: baseURL,
|
||||
uploadURL: uploadURL,
|
||||
UserAgent: defaultUserAgent,
|
||||
ExtraHeaders: make(http.Header),
|
||||
}
|
||||
|
||||
c.Account = &AccountService{client: c}
|
||||
c.Files = &FilesService{client: c}
|
||||
c.Transfers = &TransfersService{client: c}
|
||||
c.Zips = &ZipsService{client: c}
|
||||
c.Friends = &FriendsService{client: c}
|
||||
c.Events = &EventsService{client: c}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) ValidateToken(ctx context.Context) (userID *int64, err error) {
|
||||
req, err := c.NewRequest(ctx, "GET", "/v2/oauth2/validate", nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var r struct {
|
||||
UserID *int64 `json:"user_id"`
|
||||
}
|
||||
_, err = c.Do(req, &r)
|
||||
return r.UserID, err
|
||||
}
|
||||
|
||||
// NewRequest creates an API request. A relative URL can be provided via
|
||||
// relURL, which will be resolved to the BaseURL of the Client.
|
||||
func (c *Client) NewRequest(ctx context.Context, method, relURL string, body io.Reader) (*http.Request, error) {
|
||||
rel, err := url.Parse(relURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var u *url.URL
|
||||
// XXX: workaroud for upload endpoint. upload method has a different base url,
|
||||
// so we've a special case for testing purposes.
|
||||
if relURL == "/v2/files/upload" {
|
||||
u = c.uploadURL.ResolveReference(rel)
|
||||
} else {
|
||||
u = c.BaseURL.ResolveReference(rel)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, u.String(), body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
req.Header.Set("Accept", defaultMediaType)
|
||||
req.Header.Set("User-Agent", c.UserAgent)
|
||||
|
||||
// merge headers with extra headers
|
||||
for header, values := range c.ExtraHeaders {
|
||||
for _, value := range values {
|
||||
req.Header.Add(header, value)
|
||||
}
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// Do sends an API request and returns the API response. The API response is
|
||||
// JSON decoded and stored in the value pointed to by v, or returned as an
|
||||
// error if an API error has occurred. Response body is closed at all cases except
|
||||
// v is nil. If v is nil, response body is not closed and the body can be used
|
||||
// for streaming.
|
||||
func (c *Client) Do(r *http.Request, v interface{}) (*http.Response, error) {
|
||||
resp, err := c.client.Do(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = checkResponse(resp)
|
||||
if err != nil {
|
||||
// close the body at all times if there is an http error
|
||||
resp.Body.Close()
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if v == nil {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// close the body for all cases from here
|
||||
defer resp.Body.Close()
|
||||
|
||||
err = json.NewDecoder(resp.Body).Decode(v)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// checkResponse is the entrypoint to reading the API response. If the response
|
||||
// status code is not in success range, it will try to return a structured
|
||||
// error.
|
||||
func checkResponse(r *http.Response) error {
|
||||
status := r.StatusCode
|
||||
switch {
|
||||
case status >= 200 && status <= 399:
|
||||
return nil
|
||||
case status >= 400 && status <= 599:
|
||||
// server returns json
|
||||
default:
|
||||
return fmt.Errorf("unexpected status code: %d", status)
|
||||
}
|
||||
errorResponse := &ErrorResponse{Response: r}
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("body read error: %s. status: %v. Details: %v:", err, status, string(data[:250]))
|
||||
}
|
||||
if len(data) > 0 {
|
||||
err = json.Unmarshal(data, errorResponse)
|
||||
if err != nil {
|
||||
return fmt.Errorf("json decod error: %s. status: %v. Details: %v:", err, status, string(data[:250]))
|
||||
}
|
||||
}
|
||||
return errorResponse
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue