You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
202 lines
4.3 KiB
202 lines
4.3 KiB
2 years ago
|
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
|
||
|
}
|