github.com/machinebox/remoto@v0.1.2-0.20191024144331-eff21a7d321f/templates/remotohttp/server.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 10 // Package <%= def.PackageName %> contains the HTTP server for <%= def.PackageName %> services. 11 package <%= def.PackageName %> 12 13 import ( 14 "context" 15 "fmt" 16 "io" 17 "net/http" 18 "os" 19 "strconv" 20 21 "github.com/machinebox/remoto/go/remotohttp" 22 "github.com/machinebox/remoto/go/remotohttp/remototypes" 23 "github.com/pkg/errors" 24 ) 25 26 <%= for (service) in def.Services { %> 27 <%= print_comment(service.Comment) %>type <%= service.Name %> interface { 28 <%= for (method) in service.Methods { %> 29 <%= print_comment(method.Comment) %><%= method.Name %>(context.Context, *<%= method.RequestStructure.Name %>) (*<%= method.ResponseStructure.Name %>, error) 30 <% } %> 31 } 32 33 // Run is the simplest way to run the services. 34 func Run(addr string, 35 <%= for (service) in def.Services { %> <%= camelize_down(service.Name) %> <%= service.Name %>, 36 <% } %>) error { 37 server := New( 38 <%= for (service) in def.Services { %> <%= camelize_down(service.Name) %>, 39 <% } %> ) 40 if err := server.Describe(os.Stdout); err != nil { 41 return errors.Wrap(err, "describe service") 42 } 43 if err := http.ListenAndServe(addr, server); err != nil { 44 return err 45 } 46 return nil 47 } 48 49 // New makes a new remotohttp.Server with the specified services 50 // registered. 51 func New( 52 <%= for (service) in def.Services { %> <%= camelize_down(service.Name) %> <%= service.Name %>, 53 <% } %>) *remotohttp.Server { 54 server := &remotohttp.Server{ 55 OnErr: func(w http.ResponseWriter, r *http.Request, err error) { 56 fmt.Fprintf(os.Stderr, "%s %s: %s\n", r.Method, r.URL.Path, err.Error()) 57 http.Error(w, err.Error(), http.StatusInternalServerError) 58 }, 59 NotFound: http.NotFoundHandler(), 60 } 61 <%= for (service) in def.Services { %> 62 Register<%= service.Name %>Server(server, <%= camelize_down(service.Name) %>)<% } %> 63 return server 64 } 65 66 // Register<%= service.Name %>Server registers a <%= service.Name %> with a remotohttp.Server. 67 func Register<%= service.Name %>Server(server *remotohttp.Server, service <%= service.Name %>) { 68 srv := &http<%= service.Name %>Server{ 69 service: service, 70 server: server, 71 } 72 <%= for (method) in service.Methods { %>server.Register("/remoto/<%= service.Name %>.<%= method.Name %>", http.HandlerFunc(srv.handle<%= method.Name %>)) 73 <% } %> 74 } 75 76 <%= for (structure) in unique_structures(def) { %> 77 <%= print_comment(structure.Comment) %>type <%= structure.Name %> struct { 78 <%= for (field) in structure.Fields { %> 79 <%= print_comment(field.Comment) %><%= field.Name %> <%= go_type_string(field.Type) %> `json:"<%= camelize_down(field.Name) %>"` 80 <% } %> 81 } 82 83 <% } %> 84 85 // http<%= service.Name %>Server is an internal type that provides an 86 // HTTP wrapper around <%= service.Name %>. 87 type http<%= service.Name %>Server struct { 88 // service is the <%= service.Name %> being exposed by this 89 // server. 90 service <%= service.Name %> 91 // server is the remotohttp.Server that this server is 92 // registered with. 93 server *remotohttp.Server 94 } 95 96 <%= for (method) in service.Methods { %> 97 // handle<%= method.Name %> is an http.Handler wrapper for <%= service.Name %>.<%= method.Name %>. 98 func (srv *http<%= service.Name %>Server) handle<%= method.Name %>(w http.ResponseWriter, r *http.Request) { 99 var reqs []*<%= method.RequestStructure.Name %> 100 if err := remotohttp.Decode(r, &reqs); err != nil { 101 srv.server.OnErr(w, r, err) 102 return 103 } 104 <%= if (method.ResponseStructure.Name == "remototypes.FileResponse") { %> 105 // single file response 106 107 if len(reqs) != 1 { 108 if err := remotohttp.EncodeErr(w, r, errors.New("only single requests supported for file response endpoints")); err != nil { 109 srv.server.OnErr(w, r, err) 110 return 111 } 112 return 113 } 114 115 resp, err := srv.service.<%= method.Name %>(r.Context(), reqs[0]) 116 if err != nil { 117 resp.Error = err.Error() 118 if err := remotohttp.Encode(w, r, http.StatusOK, []interface{}{ resp }); err != nil { 119 srv.server.OnErr(w, r, err) 120 return 121 } 122 } 123 if resp.ContentType == "" { 124 resp.ContentType = "application/octet-stream" 125 } 126 w.Header().Set("Content-Type", resp.ContentType) 127 w.Header().Set("Content-Disposition", "attachment; filename=" + strconv.QuoteToASCII(resp.Filename)) 128 if resp.ContentLength > 0 { 129 w.Header().Set("Content-Length", strconv.Itoa(resp.ContentLength)) 130 } 131 if _, err := io.Copy(w, resp.Data); err != nil { 132 srv.server.OnErr(w, r, err) 133 return 134 } 135 <% } else { %> 136 resps := make([]<%= method.ResponseStructure.Name %>, len(reqs)) 137 for i := range reqs { 138 resp, err := srv.service.<%= method.Name %>(r.Context(), reqs[i]) 139 if err != nil { 140 resps[i].Error = err.Error() 141 continue 142 } 143 resps[i] = *resp 144 } 145 if err := remotohttp.Encode(w, r, http.StatusOK, resps); err != nil { 146 srv.server.OnErr(w, r, err) 147 return 148 } 149 <% } %> 150 }<% } %> 151 152 <% } %> 153 154 // this is here so we don't get a compiler complaints. 155 func init() { 156 var _ = remototypes.File{} 157 var _ = strconv.Itoa(0) 158 var _ = io.EOF 159 }