Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package monorail | 5 package monorail |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "bytes" | 8 "bytes" |
| 9 "encoding/json" | 9 "encoding/json" |
| 10 "fmt" | 10 "fmt" |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 39 // | 39 // |
| 40 // Methods do not implement retries. | 40 // Methods do not implement retries. |
| 41 // Use "github.com/luci/luci-go/common/errors".IsTransient to check | 41 // Use "github.com/luci/luci-go/common/errors".IsTransient to check |
| 42 // if an error is transient. | 42 // if an error is transient. |
| 43 // | 43 // |
| 44 // Client methods return an error on any grpc.CallOption. | 44 // Client methods return an error on any grpc.CallOption. |
| 45 func NewEndpointsClient(client *http.Client, url string) MonorailClient { | 45 func NewEndpointsClient(client *http.Client, url string) MonorailClient { |
| 46 return &epClient{HTTP: client, url: strings.TrimSuffix(url, "/")} | 46 return &epClient{HTTP: client, url: strings.TrimSuffix(url, "/")} |
| 47 } | 47 } |
| 48 | 48 |
| 49 func (c *epClient) get(ctx context.Context, urlSuffix string, response interface {}) error { | |
| 50 client := c.HTTP | |
| 51 if client == nil { | |
| 52 client = http.DefaultClient | |
| 53 } | |
| 54 | |
| 55 // Limit ctx deadline to timeout set in client. | |
| 56 if client.Timeout > 0 { | |
| 57 clientDeadline := clock.Now(ctx).Add(client.Timeout) | |
| 58 if deadline, ok := ctx.Deadline(); !ok || deadline.After(clientD eadline) { | |
| 59 ctx, _ = context.WithDeadline(ctx, clientDeadline) | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 // Make an HTTP request. | |
| 64 req, err := http.NewRequest("GET", c.url+urlSuffix, nil) | |
| 65 if err != nil { | |
| 66 return fmt.Errorf("could not make a request to %s: %s", req.URL, err) | |
| 67 } | |
| 68 req.Header.Set("Accept", "application/json") | |
| 69 | |
| 70 // Send the request. | |
| 71 logging.Debugf(ctx, "GET %s %s", req.URL) | |
| 72 res, err := ctxhttp.Do(ctx, client, req) | |
| 73 if err != nil { | |
| 74 return errors.WrapTransient(err) | |
| 75 } | |
| 76 defer res.Body.Close() | |
| 77 | |
| 78 // Check HTTP status code. | |
| 79 if res.StatusCode != http.StatusOK { | |
| 80 text, _ := ioutil.ReadAll(io.LimitReader(res.Body, 1024)) | |
| 81 err := fmt.Errorf("unexpected status %q. Response: %s", res.Stat us, text) | |
| 82 if res.StatusCode == http.StatusNotFound || res.StatusCode > 500 { | |
| 83 // Cloud Endpoints often flake with HTTP 404. | |
| 84 // Treat such responses transient errors. | |
| 85 err = errors.WrapTransient(err) | |
| 86 } | |
| 87 return err | |
| 88 } | |
| 89 | |
| 90 if response == nil { | |
| 91 return nil | |
| 92 } | |
| 93 return json.NewDecoder(res.Body).Decode(response) | |
| 94 } | |
| 95 | |
|
nodir
2016/06/09 04:09:28
Please don't copy paste code such big chunks of co
seanmccullough1
2016/06/09 15:01:32
Done.
| |
| 49 func (c *epClient) call(ctx context.Context, urlSuffix string, request, response interface{}) error { | 96 func (c *epClient) call(ctx context.Context, urlSuffix string, request, response interface{}) error { |
| 50 client := c.HTTP | 97 client := c.HTTP |
| 51 if client == nil { | 98 if client == nil { |
| 52 client = http.DefaultClient | 99 client = http.DefaultClient |
| 53 } | 100 } |
| 54 | 101 |
| 55 // Limit ctx deadline to timeout set in client. | 102 // Limit ctx deadline to timeout set in client. |
| 56 if client.Timeout > 0 { | 103 if client.Timeout > 0 { |
| 57 clientDeadline := clock.Now(ctx).Add(client.Timeout) | 104 clientDeadline := clock.Now(ctx).Add(client.Timeout) |
| 58 if deadline, ok := ctx.Deadline(); !ok || deadline.After(clientD eadline) { | 105 if deadline, ok := ctx.Deadline(); !ok || deadline.After(clientD eadline) { |
| 59 ctx, _ = context.WithDeadline(ctx, clientDeadline) | 106 ctx, _ = context.WithDeadline(ctx, clientDeadline) |
| 60 } | 107 } |
| 61 } | 108 } |
| 62 | 109 |
| 63 // Convert request object to JSON. | 110 // Convert request object to JSON. |
| 64 reqBuf := &bytes.Buffer{} | 111 reqBuf := &bytes.Buffer{} |
| 65 if request != nil { | 112 if request != nil { |
| 66 if err := json.NewEncoder(reqBuf).Encode(request); err != nil { | 113 if err := json.NewEncoder(reqBuf).Encode(request); err != nil { |
| 67 return err | 114 return err |
| 68 } | 115 } |
| 69 } | 116 } |
| 70 | 117 |
| 71 // Make an HTTP request. | 118 // Make an HTTP request. |
| 72 » req, err := http.NewRequest("POST", c.url + urlSuffix, reqBuf) | 119 » req, err := http.NewRequest("POST", c.url+urlSuffix, reqBuf) |
| 73 if err != nil { | 120 if err != nil { |
| 74 return fmt.Errorf("could not make a request to %s: %s", req.URL, err) | 121 return fmt.Errorf("could not make a request to %s: %s", req.URL, err) |
| 75 } | 122 } |
| 76 req.Header.Set("Content-Type", "application/json") | 123 req.Header.Set("Content-Type", "application/json") |
| 77 req.Header.Set("Accept", "application/json") | 124 req.Header.Set("Accept", "application/json") |
| 78 | 125 |
| 79 // Send the request. | 126 // Send the request. |
| 80 logging.Debugf(ctx, "POST %s %s", req.URL, reqBuf.Bytes()) | 127 logging.Debugf(ctx, "POST %s %s", req.URL, reqBuf.Bytes()) |
| 81 res, err := ctxhttp.Do(ctx, client, req) | 128 res, err := ctxhttp.Do(ctx, client, req) |
| 82 if err != nil { | 129 if err != nil { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 115 } | 162 } |
| 116 | 163 |
| 117 func (c *epClient) InsertComment(ctx context.Context, req *InsertCommentRequest, options ...grpc.CallOption) (*InsertCommentResponse, error) { | 164 func (c *epClient) InsertComment(ctx context.Context, req *InsertCommentRequest, options ...grpc.CallOption) (*InsertCommentResponse, error) { |
| 118 if err := checkOptions(options); err != nil { | 165 if err := checkOptions(options); err != nil { |
| 119 return nil, err | 166 return nil, err |
| 120 } | 167 } |
| 121 url := fmt.Sprintf("/projects/%s/issues/%d/comments", req.Issue.ProjectI d, req.Issue.IssueId) | 168 url := fmt.Sprintf("/projects/%s/issues/%d/comments", req.Issue.ProjectI d, req.Issue.IssueId) |
| 122 return &InsertCommentResponse{}, c.call(ctx, url, req.Comment, nil) | 169 return &InsertCommentResponse{}, c.call(ctx, url, req.Comment, nil) |
| 123 } | 170 } |
| 124 | 171 |
| 172 func (c *epClient) IssuesList(ctx context.Context, req *IssuesListRequest, optio ns ...grpc.CallOption) (*IssuesListResponse, error) { | |
| 173 if err := checkOptions(options); err != nil { | |
| 174 return nil, err | |
| 175 } | |
| 176 url := fmt.Sprintf("/projects/%s/issues?can=open&q=%s", req.ProjectId, r eq.Q) | |
|
nodir
2016/06/09 04:09:28
What about all the other fields? Either don't decl
nodir
2016/06/09 04:09:28
req.Can should be used instead of hardcoded open
seanmccullough1
2016/06/09 15:01:32
Done.
seanmccullough1
2016/06/09 15:01:32
Done.
| |
| 177 res := &IssuesListResponse{} | |
| 178 err := c.get(ctx, url, res) | |
| 179 if err != nil { | |
| 180 return nil, err | |
| 181 } | |
| 182 return res, nil | |
| 183 } | |
| 184 | |
| 125 func checkOptions(options []grpc.CallOption) error { | 185 func checkOptions(options []grpc.CallOption) error { |
| 126 if len(options) > 0 { | 186 if len(options) > 0 { |
| 127 return errGrpcOptions | 187 return errGrpcOptions |
| 128 } | 188 } |
| 129 return nil | 189 return nil |
| 130 } | 190 } |
| OLD | NEW |