diff options
Diffstat (limited to 'vendor/github.com/nlopes/slack/misc.go')
-rw-r--r-- | vendor/github.com/nlopes/slack/misc.go | 135 |
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) } |