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  }