mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
240 lines
5.1 KiB
Go
240 lines
5.1 KiB
Go
// Copyright © 2016 Aaron Longwell
|
|
//
|
|
// Use of this source code is governed by an MIT licese.
|
|
// Details in the LICENSE file.
|
|
|
|
package trello
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
const DEFAULT_BASEURL = "https://api.trello.com/1"
|
|
|
|
type Client struct {
|
|
Client *http.Client
|
|
Logger logger
|
|
BaseURL string
|
|
Key string
|
|
Token string
|
|
throttle <-chan time.Time
|
|
testMode bool
|
|
ctx context.Context
|
|
}
|
|
|
|
type logger interface {
|
|
Debugf(string, ...interface{})
|
|
}
|
|
|
|
func NewClient(key, token string) *Client {
|
|
return &Client{
|
|
Client: http.DefaultClient,
|
|
BaseURL: DEFAULT_BASEURL,
|
|
Key: key,
|
|
Token: token,
|
|
throttle: time.Tick(time.Second / 8), // Actually 10/second, but we're extra cautious
|
|
testMode: false,
|
|
ctx: context.Background(),
|
|
}
|
|
}
|
|
|
|
func (c *Client) WithContext(ctx context.Context) *Client {
|
|
newC := *c
|
|
newC.ctx = ctx
|
|
return &newC
|
|
}
|
|
|
|
func (c *Client) Throttle() {
|
|
if !c.testMode {
|
|
<-c.throttle
|
|
}
|
|
}
|
|
|
|
func (c *Client) Get(path string, args Arguments, target interface{}) error {
|
|
|
|
// Trello prohibits more than 10 seconds/second per token
|
|
c.Throttle()
|
|
|
|
params := args.ToURLValues()
|
|
c.log("[trello] GET %s?%s", path, params.Encode())
|
|
|
|
if c.Key != "" {
|
|
params.Set("key", c.Key)
|
|
}
|
|
|
|
if c.Token != "" {
|
|
params.Set("token", c.Token)
|
|
}
|
|
|
|
url := fmt.Sprintf("%s/%s", c.BaseURL, path)
|
|
urlWithParams := fmt.Sprintf("%s?%s", url, params.Encode())
|
|
|
|
req, err := http.NewRequest("GET", urlWithParams, nil)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "Invalid GET request %s", url)
|
|
}
|
|
req = req.WithContext(c.ctx)
|
|
|
|
resp, err := c.Client.Do(req)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "HTTP request failure on %s", url)
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != 200 {
|
|
return makeHttpClientError(url, resp)
|
|
}
|
|
|
|
decoder := json.NewDecoder(resp.Body)
|
|
err = decoder.Decode(target)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "JSON decode failed on %s", url)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) Put(path string, args Arguments, target interface{}) error {
|
|
|
|
// Trello prohibits more than 10 seconds/second per token
|
|
c.Throttle()
|
|
|
|
params := args.ToURLValues()
|
|
c.log("[trello] PUT %s?%s", path, params.Encode())
|
|
|
|
if c.Key != "" {
|
|
params.Set("key", c.Key)
|
|
}
|
|
|
|
if c.Token != "" {
|
|
params.Set("token", c.Token)
|
|
}
|
|
|
|
url := fmt.Sprintf("%s/%s", c.BaseURL, path)
|
|
urlWithParams := fmt.Sprintf("%s?%s", url, params.Encode())
|
|
|
|
req, err := http.NewRequest("PUT", urlWithParams, nil)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "Invalid PUT request %s", url)
|
|
}
|
|
|
|
resp, err := c.Client.Do(req)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "HTTP request failure on %s", url)
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != 200 {
|
|
return makeHttpClientError(url, resp)
|
|
}
|
|
|
|
decoder := json.NewDecoder(resp.Body)
|
|
err = decoder.Decode(target)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "JSON decode failed on %s", url)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) Post(path string, args Arguments, target interface{}) error {
|
|
|
|
// Trello prohibits more than 10 seconds/second per token
|
|
c.Throttle()
|
|
|
|
params := args.ToURLValues()
|
|
c.log("[trello] POST %s?%s", path, params.Encode())
|
|
|
|
if c.Key != "" {
|
|
params.Set("key", c.Key)
|
|
}
|
|
|
|
if c.Token != "" {
|
|
params.Set("token", c.Token)
|
|
}
|
|
|
|
url := fmt.Sprintf("%s/%s", c.BaseURL, path)
|
|
urlWithParams := fmt.Sprintf("%s?%s", url, params.Encode())
|
|
|
|
req, err := http.NewRequest("POST", urlWithParams, nil)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "Invalid POST request %s", url)
|
|
}
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
resp, err := c.Client.Do(req)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "HTTP request failure on %s", url)
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
b, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "HTTP Read error on response for %s", url)
|
|
}
|
|
|
|
decoder := json.NewDecoder(bytes.NewBuffer(b))
|
|
err = decoder.Decode(target)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "JSON decode failed on %s:\n%s", url, string(b))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) Delete(path string, args Arguments, target interface{}) error {
|
|
|
|
c.Throttle()
|
|
|
|
params := args.ToURLValues()
|
|
c.log("[trello] DELETE %s?%s", path, params.Encode())
|
|
|
|
if c.Key != "" {
|
|
params.Set("key", c.Key)
|
|
}
|
|
|
|
if c.Token != "" {
|
|
params.Set("token", c.Token)
|
|
}
|
|
|
|
url := fmt.Sprintf("%s/%s", c.BaseURL, path)
|
|
urlWithParams := fmt.Sprintf("%s?%s", url, params.Encode())
|
|
|
|
req, err := http.NewRequest("DELETE", urlWithParams, nil)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "Invalid DELETE request %s", url)
|
|
}
|
|
|
|
resp, err := c.Client.Do(req)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "HTTP request failure on %s", url)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
b, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "HTTP Read error on response for %s", url)
|
|
}
|
|
|
|
decoder := json.NewDecoder(bytes.NewBuffer(b))
|
|
err = decoder.Decode(target)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "JSON decode failed on %s:\n%s", url, string(b))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) log(format string, args ...interface{}) {
|
|
if c.Logger != nil {
|
|
c.Logger.Debugf(format, args...)
|
|
}
|
|
}
|