github.com/machinebox/remoto@v0.1.2-0.20191024144331-eff21a7d321f/templates/remotohttp/client.go.plush (about) 1 // Code generated by Remoto; DO NOT EDIT. 2 <% 3 4 let serverName = fn(serviceName) { 5 return serviceName + "Server" 6 } 7 8 %> 9 package <%= def.PackageName %> 10 11 import ( 12 "context" 13 "encoding/json" 14 "io" 15 "io/ioutil" 16 "mime/multipart" 17 "net/http" 18 "strconv" 19 20 "github.com/machinebox/remoto/remototypes" 21 "github.com/oxtoacart/bpool" 22 "github.com/pkg/errors" 23 ) 24 25 <%= for (service) in def.Services { %> 26 // <%= service.Name %>Client accesses remote <%= service.Name %> services. 27 type <%= service.Name %>Client struct { 28 // endpoint is the HTTP endpoint of the remote server. 29 endpoint string 30 // httpclient is the http.Client to use to make requests. 31 httpclient *http.Client 32 // bufs is a buffer pool 33 bufs *bpool.BufferPool 34 } 35 36 // New<%= service.Name %>Client makes a new <%= service.Name %>Client that will 37 // use the specified http.Client to make requests. 38 func New<%= service.Name %>Client(endpoint string, client *http.Client) *<%= service.Name %>Client { 39 return &<%= service.Name %>Client{ 40 endpoint: endpoint, 41 httpclient: client, 42 bufs: bpool.NewBufferPool(48), 43 } 44 } 45 46 <%= for (method) in service.Methods { %> 47 <%= if (method.ResponseStructure.Name == "remototypes.FileResponse") { %> 48 <%= print_comment(method.Comment) %>func (c *<%= service.Name %>Client) <%= method.Name %>(ctx context.Context, request *<%= method.RequestStructure.Name %>) (io.ReadCloser, error) { 49 b, err := json.Marshal([]interface{}{ request }) 50 if err != nil { 51 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: encode request") 52 } 53 buf := c.bufs.Get() 54 defer c.bufs.Put(buf) 55 w := multipart.NewWriter(buf) 56 w.WriteField("json", string(b)) 57 if files, ok := ctx.Value(contextKeyFiles).(map[string]file); ok { 58 for fieldname, file := range files { 59 f, err := w.CreateFormFile(fieldname, file.filename) 60 if err != nil { 61 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: create form file") 62 } 63 if _, err := io.Copy(f, file.r); err != nil { 64 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: reading file") 65 } 66 select { 67 case <-ctx.Done(): 68 return nil, ctx.Err() 69 default: 70 } 71 } 72 } 73 if err := w.Close(); err != nil { 74 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: write") 75 } 76 req, err := http.NewRequest(http.MethodPost, c.endpoint + "/remoto/<%= service.Name %>.<%= method.Name %>", buf) 77 if err != nil { 78 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: new request") 79 } 80 req.Header.Set("Accept", "application/json; charset=utf-8") 81 req.Header.Set("Content-Type", w.FormDataContentType()) 82 req = req.WithContext(ctx) 83 resp, err := c.httpclient.Do(req) 84 if err != nil { 85 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: do") 86 } 87 if resp.StatusCode != http.StatusOK { 88 resp.Body.Close() 89 return nil, errors.Errorf("<%= service.Name %>Client.<%= method.Name %>: remote service returned %s", resp.Status) 90 } 91 return resp.Body, nil 92 } 93 <% } else { %> 94 <%= print_comment(method.Comment) %>func (c *<%= service.Name %>Client) <%= method.Name %>(ctx context.Context, request *<%= method.RequestStructure.Name %>) (*<%= method.ResponseStructure.Name %>, error) { 95 resp, err := c.<%= method.Name %>Multi(ctx, []*<%= method.RequestStructure.Name %>{request}) 96 if err != nil { 97 return nil, err 98 } 99 if len(resp) == 0 { 100 return nil, errors.New("<%= service.Name %>Client.<%= method.Name %>: no response") 101 } 102 return resp[0], nil 103 } 104 105 func (c *<%= service.Name %>Client) <%= method.Name %>Multi(ctx context.Context, requests []*<%= method.RequestStructure.Name %>) ([]*<%= method.ResponseStructure.Name %>, error) { 106 b, err := json.Marshal(requests) 107 if err != nil { 108 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: encode request") 109 } 110 buf := c.bufs.Get() 111 defer c.bufs.Put(buf) 112 w := multipart.NewWriter(buf) 113 w.WriteField("json", string(b)) 114 if files, ok := ctx.Value(contextKeyFiles).(map[string]file); ok { 115 for fieldname, file := range files { 116 f, err := w.CreateFormFile(fieldname, file.filename) 117 if err != nil { 118 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: create form file") 119 } 120 if _, err := io.Copy(f, file.r); err != nil { 121 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: reading file") 122 } 123 select { 124 case <-ctx.Done(): 125 return nil, ctx.Err() 126 default: 127 } 128 } 129 } 130 if err := w.Close(); err != nil { 131 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: write") 132 } 133 req, err := http.NewRequest(http.MethodPost, c.endpoint + "/remoto/<%= service.Name %>.<%= method.Name %>", buf) 134 if err != nil { 135 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: new request") 136 } 137 req.Header.Set("Accept", "application/json; charset=utf-8") 138 req.Header.Set("Content-Type", w.FormDataContentType()) 139 req = req.WithContext(ctx) 140 resp, err := c.httpclient.Do(req) 141 if err != nil { 142 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: do") 143 } 144 if resp.StatusCode != http.StatusOK { 145 resp.Body.Close() 146 return nil, errors.Errorf("<%= service.Name %>Client.<%= method.Name %>: remote service returned %s", resp.Status) 147 } 148 b, err = ioutil.ReadAll(resp.Body) 149 resp.Body.Close() 150 if err != nil { 151 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: read response body") 152 } 153 var resps []*<%= method.ResponseStructure.Name %> 154 if err := json.Unmarshal(b, &resps); err != nil { 155 return nil, errors.Wrap(err, "<%= service.Name %>Client.<%= method.Name %>: decode response body") 156 } 157 return resps, nil 158 } 159 <% } %> 160 <% } %> 161 <% } %> 162 163 <%= for (structure) in unique_structures(def) { %> 164 <%= print_comment(structure.Comment) %>type <%= structure.Name %> struct { 165 <%= for (field) in structure.Fields { %> 166 <%= print_comment(field.Comment) %><%= field.Name %> <%= go_type_string(field.Type) %> `json:"<%= camelize_down(field.Name) %>"`<% } %> 167 } 168 169 <%= for (field) in structure.Fields { %> 170 <%= if (field.Type.Name == "remototypes.File" && !structure.IsResponseObject) { %> 171 // Set<%= field.Name %> sets the file for the <%= field.Name %> field. 172 func (s *<%= structure.Name %>) Set<%= field.Name %>(ctx context.Context, filename string, r io.Reader) context.Context { 173 files, ok := ctx.Value(contextKeyFiles).(map[string]file) 174 if !ok { 175 files = make(map[string]file) 176 } 177 fieldname := "files["+ strconv.Itoa(len(files)) + "]" 178 files[fieldname] = file{r: r, filename: filename} 179 ctx = context.WithValue(ctx, contextKeyFiles, files) 180 s.<%= field.Name %> = remototypes.File{ 181 Fieldname: fieldname, 182 Filename: filename, 183 } 184 return ctx 185 } 186 <% } %> 187 <%= if (field.Type.Name == "remototypes.File" && !structure.IsRequestObject) { %> 188 // Open<%= field.Name %> opens the file from the response. 189 func (s *<%= structure.Name %>) Open<%= field.Name %>(ctx context.Context) (io.Reader, error) { 190 return nil, nil 191 } 192 <% } %> 193 <% } %> 194 195 <% } %> 196 197 // contextKey is a local context key type. 198 // see https://medium.com/@matryer/context-keys-in-go-5312346a868d 199 type contextKey string 200 201 func (c contextKey) String() string { 202 return "remoto context key: " + string(c) 203 } 204 205 // contextKeyFiles is the context key for the request files. 206 var contextKeyFiles = contextKey("files") 207 208 // file holds info about a file in the context, including 209 // the io.Reader where the contents will be read from. 210 type file struct { 211 r io.Reader 212 filename string 213 } 214 215 // this is here so we don't get a compiler complaints. 216 func init() { 217 var _ = remototypes.File{} 218 var _ = strconv.Itoa(0) 219 var _ = ioutil.Discard 220 }