github.com/machinebox/remoto@v0.1.2-0.20191024144331-eff21a7d321f/go/remotohttp/server.go (about) 1 package remotohttp 2 3 import ( 4 "context" 5 "io" 6 "net/http" 7 "sync" 8 9 "github.com/machinebox/remoto/go/remotohttp/remototypes" 10 ) 11 12 // Server is an HTTP server for serving Remoto requests. 13 type Server struct { 14 handlers sync.Map 15 16 // NotFound handles 404 responses. 17 NotFound http.Handler 18 19 // OnErr is called when there has been a system level error, 20 // like encoding/decoding. 21 OnErr func(w http.ResponseWriter, r *http.Request, err error) 22 } 23 24 // NewServer makes a new Server. 25 func NewServer() *Server { 26 return &Server{ 27 NotFound: http.NotFoundHandler(), 28 OnErr: func(w http.ResponseWriter, r *http.Request, err error) { 29 http.Error(w, err.Error(), http.StatusInternalServerError) 30 }, 31 } 32 } 33 34 // Register registers the path with the http.Handler. 35 func (srv *Server) Register(path string, fn http.Handler) { 36 srv.handlers.Store(path, fn) 37 } 38 39 // ServeHTTP calls the registered handler 40 func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { 41 if r.Method != http.MethodPost { 42 if srv.NotFound != nil { 43 srv.NotFound.ServeHTTP(w, r) 44 return 45 } 46 http.NotFound(w, r) 47 return 48 } 49 h, ok := srv.handlers.Load(r.URL.Path) 50 if !ok { 51 if srv.NotFound != nil { 52 srv.NotFound.ServeHTTP(w, r) 53 return 54 } 55 http.NotFound(w, r) 56 return 57 } 58 handler, ok := h.(http.Handler) 59 if !ok { 60 panic("remotohttp: handler is the wrong type") 61 } 62 opener := func(_ context.Context, file remototypes.File) (io.ReadCloser, error) { 63 f, _, err := r.FormFile(file.Fieldname) 64 return f, err 65 } 66 r = r.WithContext(remototypes.WithOpener(r.Context(), opener)) 67 handler.ServeHTTP(w, r) 68 } 69 70 // Describe an overview of the endpoints to the specified io.Writer. 71 func (srv *Server) Describe(w io.Writer) error { 72 var err error 73 srv.handlers.Range(func(k, v interface{}) bool { 74 if _, err = io.WriteString(w, "endpoint: "+k.(string)+"\n"); err != nil { 75 return false 76 } 77 return true 78 }) 79 return err 80 } 81 82 // Error is an error wrapper for responses. 83 type Error struct { 84 Err error `json:"error"` 85 }