package http import ( "context" "encoding/json" "encoding/xml" "git.diulo.com/mogfee/kit/middleware" "git.diulo.com/mogfee/kit/transport" "git.diulo.com/mogfee/kit/transport/http/binding" "github.com/gorilla/mux" "io" "net/http" "net/url" "time" ) type Context interface { context.Context Vars() url.Values Query() url.Values Form() url.Values Header() http.Header Request() *http.Request Response() http.ResponseWriter Middleware(middleware.Handler) middleware.Handler Bind(interface{}) error BindVars(interface{}) error BindQuery(interface{}) error BindForm(interface{}) error Returns(interface{}, error) error Result(int, interface{}) error JSON(int, interface{}) error XML(int, interface{}) error String(int, string) error Blob(int, string, []byte) error Stream(int, string, io.Reader) error Reset(http.ResponseWriter, *http.Request) } type responseWriter struct { code int w http.ResponseWriter } func (r *responseWriter) Header() http.Header { return r.w.Header() } func (r *responseWriter) Write(bytes []byte) (int, error) { r.w.WriteHeader(r.code) return r.w.Write(bytes) } func (r *responseWriter) WriteHeader(statusCode int) { r.code = statusCode } func (r *responseWriter) reset(res http.ResponseWriter) { r.w = res r.code = http.StatusOK } type wrapper struct { router *Router req *http.Request res http.ResponseWriter w responseWriter } func (w *wrapper) Deadline() (deadline time.Time, ok bool) { if w.req == nil { return time.Time{}, false } return w.req.Context().Deadline() } func (w *wrapper) Done() <-chan struct{} { if w.req == nil { return nil } return w.req.Context().Done() } func (w *wrapper) Err() error { if w.req == nil { return context.Canceled } return w.req.Context().Err() } func (w *wrapper) Value(key any) any { if w.req == nil { return nil } return w.req.Context().Value(key) } func (w *wrapper) Vars() url.Values { raws := mux.Vars(w.req) vars := make(url.Values, len(raws)) for k, v := range raws { vars[k] = []string{v} } return vars } func (w *wrapper) Query() url.Values { return w.req.URL.Query() } func (w *wrapper) Form() url.Values { if err := w.req.ParseForm(); err != nil { return url.Values{} } return w.req.Form } func (w *wrapper) Header() http.Header { return w.req.Header } func (w *wrapper) Request() *http.Request { return w.req } func (w *wrapper) Response() http.ResponseWriter { return w.res } func (w *wrapper) Middleware(handler middleware.Handler) middleware.Handler { if tr, ok := transport.FromServerContext(w.req.Context()); ok { return middleware.Chain(w.router.srv.middleware.Match(tr.Operation())...)(handler) } return middleware.Chain(w.router.srv.middleware.Match(w.req.URL.Path)...)(handler) } func (w *wrapper) Bind(i any) error { return w.router.srv.decBody(w.req, i) } func (w *wrapper) BindVars(i interface{}) error { return w.router.srv.decVars(w.req, i) } func (w *wrapper) BindQuery(i interface{}) error { return w.router.srv.decQuery(w.req, i) } func (w *wrapper) BindForm(i interface{}) error { return binding.BindForm(w.req, i) } func (w *wrapper) Returns(i interface{}, err error) error { if err != nil { return err } return w.router.srv.enc(&w.w, w.req, i) } func (w *wrapper) Result(i int, i2 interface{}) error { w.w.WriteHeader(i) return w.router.srv.enc(&w.w, w.req, i2) } func (w *wrapper) JSON(i int, i2 interface{}) error { w.res.Header().Set("Content-Type", "application/json") w.res.WriteHeader(i) return json.NewEncoder(w.res).Encode(i2) } func (w *wrapper) XML(i int, i2 interface{}) error { w.res.Header().Set("Content-Type", "application/xml") w.res.WriteHeader(i) return xml.NewEncoder(w.res).Encode(i2) } func (w *wrapper) String(i int, s string) error { w.res.Header().Set("Content-Type", "text/plain") w.res.WriteHeader(i) _, err := w.res.Write([]byte(s)) return err } func (w *wrapper) Blob(i int, s string, bytes []byte) error { w.res.Header().Set("Content-Type", s) w.res.WriteHeader(i) _, err := w.res.Write(bytes) return err } func (w *wrapper) Stream(i int, s string, reader io.Reader) error { w.res.Header().Set("Content-Type", s) w.res.WriteHeader(i) _, err := io.Copy(w.res, reader) return err } func (w *wrapper) Reset(writer http.ResponseWriter, request *http.Request) { w.w.reset(writer) w.res = writer w.req = request }