summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/nlopes/slack/misc.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/nlopes/slack/misc.go')
-rw-r--r--vendor/github.com/nlopes/slack/misc.go135
1 files changed, 86 insertions, 49 deletions
diff --git a/vendor/github.com/nlopes/slack/misc.go b/vendor/github.com/nlopes/slack/misc.go
index e890aa8f..69103384 100644
--- a/vendor/github.com/nlopes/slack/misc.go
+++ b/vendor/github.com/nlopes/slack/misc.go
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/json"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -18,29 +19,41 @@ import (
"time"
)
-// HTTPRequester defines the minimal interface needed for an http.Client to be implemented.
-//
-// Use it in conjunction with the SetHTTPClient function to allow for other capabilities
-// like a tracing http.Client
-type HTTPRequester interface {
- Do(*http.Request) (*http.Response, error)
+type SlackResponse struct {
+ Ok bool `json:"ok"`
+ Error string `json:"error"`
}
-var customHTTPClient HTTPRequester
+func (t SlackResponse) Err() error {
+ if t.Ok {
+ return nil
+ }
+
+ // handle pure text based responses like chat.post
+ // which while they have a slack response in their data structure
+ // it doesn't actually get set during parsing.
+ if strings.TrimSpace(t.Error) == "" {
+ return nil
+ }
-// HTTPClient sets a custom http.Client
-// deprecated: in favor of SetHTTPClient()
-var HTTPClient = &http.Client{}
+ return errors.New(t.Error)
+}
-type WebResponse struct {
- Ok bool `json:"ok"`
- Error *WebError `json:"error"`
+// StatusCodeError represents an http response error.
+// type httpStatusCode interface { HTTPStatusCode() int } to handle it.
+type statusCodeError struct {
+ Code int
+ Status string
}
-type WebError string
+func (t statusCodeError) Error() string {
+ // TODO: this is a bad error string, should clean it up with a breaking changes
+ // merger.
+ return fmt.Sprintf("Slack server error: %s.", t.Status)
+}
-func (s WebError) Error() string {
- return string(s)
+func (t statusCodeError) HTTPStatusCode() int {
+ return t.Code
}
type RateLimitedError struct {
@@ -77,7 +90,7 @@ func fileUploadReq(ctx context.Context, path, fieldname, filename string, values
return req, nil
}
-func parseResponseBody(body io.ReadCloser, intf *interface{}, debug bool) error {
+func parseResponseBody(body io.ReadCloser, intf interface{}, debug bool) error {
response, err := ioutil.ReadAll(body)
if err != nil {
return err
@@ -88,10 +101,10 @@ func parseResponseBody(body io.ReadCloser, intf *interface{}, debug bool) error
logger.Printf("parseResponseBody: %s\n", string(response))
}
- return json.Unmarshal(response, &intf)
+ return json.Unmarshal(response, intf)
}
-func postLocalWithMultipartResponse(ctx context.Context, path, fpath, fieldname string, values url.Values, intf interface{}, debug bool) error {
+func postLocalWithMultipartResponse(ctx context.Context, client HTTPRequester, path, fpath, fieldname string, values url.Values, intf interface{}, debug bool) error {
fullpath, err := filepath.Abs(fpath)
if err != nil {
return err
@@ -101,16 +114,16 @@ func postLocalWithMultipartResponse(ctx context.Context, path, fpath, fieldname
return err
}
defer file.Close()
- return postWithMultipartResponse(ctx, path, filepath.Base(fpath), fieldname, values, file, intf, debug)
+ return postWithMultipartResponse(ctx, client, path, filepath.Base(fpath), fieldname, values, file, intf, debug)
}
-func postWithMultipartResponse(ctx context.Context, path, name, fieldname string, values url.Values, r io.Reader, intf interface{}, debug bool) error {
+func postWithMultipartResponse(ctx context.Context, client HTTPRequester, path, name, fieldname string, values url.Values, r io.Reader, intf interface{}, debug bool) error {
req, err := fileUploadReq(ctx, SLACK_API+path, fieldname, name, values, r)
if err != nil {
return err
}
req = req.WithContext(ctx)
- resp, err := getHTTPClient().Do(req)
+ resp, err := client.Do(req)
if err != nil {
return err
}
@@ -127,22 +140,15 @@ func postWithMultipartResponse(ctx context.Context, path, name, fieldname string
// Slack seems to send an HTML body along with 5xx error codes. Don't parse it.
if resp.StatusCode != http.StatusOK {
logResponse(resp, debug)
- return fmt.Errorf("Slack server error: %s.", resp.Status)
+ return statusCodeError{Code: resp.StatusCode, Status: resp.Status}
}
- return parseResponseBody(resp.Body, &intf, debug)
+ return parseResponseBody(resp.Body, intf, debug)
}
-func postForm(ctx context.Context, endpoint string, values url.Values, intf interface{}, debug bool) error {
- reqBody := strings.NewReader(values.Encode())
- req, err := http.NewRequest("POST", endpoint, reqBody)
- if err != nil {
- return err
- }
- req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
-
+func doPost(ctx context.Context, client HTTPRequester, req *http.Request, intf interface{}, debug bool) error {
req = req.WithContext(ctx)
- resp, err := getHTTPClient().Do(req)
+ resp, err := client.Do(req)
if err != nil {
return err
}
@@ -159,19 +165,43 @@ func postForm(ctx context.Context, endpoint string, values url.Values, intf inte
// Slack seems to send an HTML body along with 5xx error codes. Don't parse it.
if resp.StatusCode != http.StatusOK {
logResponse(resp, debug)
- return fmt.Errorf("Slack server error: %s.", resp.Status)
+ return statusCodeError{Code: resp.StatusCode, Status: resp.Status}
+ }
+
+ return parseResponseBody(resp.Body, intf, debug)
+}
+
+// post JSON.
+func postJSON(ctx context.Context, client HTTPRequester, endpoint, token string, json []byte, intf interface{}, debug bool) error {
+ reqBody := bytes.NewBuffer(json)
+ req, err := http.NewRequest("POST", endpoint, reqBody)
+ if err != nil {
+ return err
}
+ req.Header.Set("Content-Type", "application/json")
+ req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
+ return doPost(ctx, client, req, intf, debug)
+}
- return parseResponseBody(resp.Body, &intf, debug)
+// post a url encoded form.
+func postForm(ctx context.Context, client HTTPRequester, endpoint string, values url.Values, intf interface{}, debug bool) error {
+ reqBody := strings.NewReader(values.Encode())
+ req, err := http.NewRequest("POST", endpoint, reqBody)
+ if err != nil {
+ return err
+ }
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ return doPost(ctx, client, req, intf, debug)
}
-func post(ctx context.Context, path string, values url.Values, intf interface{}, debug bool) error {
- return postForm(ctx, SLACK_API+path, values, intf, debug)
+// post to a slack web method.
+func postSlackMethod(ctx context.Context, client HTTPRequester, path string, values url.Values, intf interface{}, debug bool) error {
+ return postForm(ctx, client, SLACK_API+path, values, intf, debug)
}
-func parseAdminResponse(ctx context.Context, method string, teamName string, values url.Values, intf interface{}, debug bool) error {
+func parseAdminResponse(ctx context.Context, client HTTPRequester, method string, teamName string, values url.Values, intf interface{}, debug bool) error {
endpoint := fmt.Sprintf(SLACK_WEB_API_FORMAT, teamName, method, time.Now().Unix())
- return postForm(ctx, endpoint, values, intf, debug)
+ return postForm(ctx, client, endpoint, values, intf, debug)
}
func logResponse(resp *http.Response, debug bool) error {
@@ -187,17 +217,24 @@ func logResponse(resp *http.Response, debug bool) error {
return nil
}
-func getHTTPClient() HTTPRequester {
- if customHTTPClient != nil {
- return customHTTPClient
- }
+func okJSONHandler(rw http.ResponseWriter, r *http.Request) {
+ rw.Header().Set("Content-Type", "application/json")
+ response, _ := json.Marshal(SlackResponse{
+ Ok: true,
+ })
+ rw.Write(response)
+}
+
+type errorString string
- return HTTPClient
+func (t errorString) Error() string {
+ return string(t)
}
-// SetHTTPClient allows you to specify a custom http.Client
-// Use this instead of the package level HTTPClient variable if you want to use a custom client like the
-// Stackdriver Trace HTTPClient https://godoc.org/cloud.google.com/go/trace#HTTPClient
-func SetHTTPClient(client HTTPRequester) {
- customHTTPClient = client
+// timerReset safely reset a timer, see time.Timer.Reset for details.
+func timerReset(t *time.Timer, d time.Duration) {
+ if !t.Stop() {
+ <-t.C
+ }
+ t.Reset(d)
}