github.com/kotovmak/go-admin@v1.1.1/adapter/chi/chi.go (about) 1 // Copyright 2019 GoAdmin Core Team. All rights reserved. 2 // Use of this source code is governed by a Apache-2.0 style 3 // license that can be found in the LICENSE file. 4 5 package chi 6 7 import ( 8 "bytes" 9 "errors" 10 "net/http" 11 "net/url" 12 "regexp" 13 "strings" 14 15 "github.com/go-chi/chi/v5" 16 "github.com/kotovmak/go-admin/adapter" 17 "github.com/kotovmak/go-admin/context" 18 "github.com/kotovmak/go-admin/engine" 19 cfg "github.com/kotovmak/go-admin/modules/config" 20 "github.com/kotovmak/go-admin/plugins" 21 "github.com/kotovmak/go-admin/plugins/admin/models" 22 "github.com/kotovmak/go-admin/plugins/admin/modules/constant" 23 "github.com/kotovmak/go-admin/template/types" 24 ) 25 26 // Chi structure value is a Chi GoAdmin adapter. 27 type Chi struct { 28 adapter.BaseAdapter 29 ctx Context 30 app *chi.Mux 31 } 32 33 func init() { 34 engine.Register(new(Chi)) 35 } 36 37 // User implements the method Adapter.User. 38 func (ch *Chi) User(ctx interface{}) (models.UserModel, bool) { 39 return ch.GetUser(ctx, ch) 40 } 41 42 // Use implements the method Adapter.Use. 43 func (ch *Chi) Use(app interface{}, plugs []plugins.Plugin) error { 44 return ch.GetUse(app, plugs, ch) 45 } 46 47 // Content implements the method Adapter.Content. 48 func (ch *Chi) Content(ctx interface{}, getPanelFn types.GetPanelFn, fn context.NodeProcessor, btns ...types.Button) { 49 ch.GetContent(ctx, getPanelFn, ch, btns, fn) 50 } 51 52 type HandlerFunc func(ctx Context) (types.Panel, error) 53 54 func Content(handler HandlerFunc) http.HandlerFunc { 55 return func(writer http.ResponseWriter, request *http.Request) { 56 ctx := Context{ 57 Request: request, 58 Response: writer, 59 } 60 engine.Content(ctx, func(ctx interface{}) (types.Panel, error) { 61 return handler(ctx.(Context)) 62 }) 63 } 64 } 65 66 // SetApp implements the method Adapter.SetApp. 67 func (ch *Chi) SetApp(app interface{}) error { 68 var ( 69 eng *chi.Mux 70 ok bool 71 ) 72 if eng, ok = app.(*chi.Mux); !ok { 73 return errors.New("chi adapter SetApp: wrong parameter") 74 } 75 ch.app = eng 76 return nil 77 } 78 79 // AddHandler implements the method Adapter.AddHandler. 80 func (ch *Chi) AddHandler(method, path string, handlers context.Handlers) { 81 url := path 82 reg1 := regexp.MustCompile(":(.*?)/") 83 reg2 := regexp.MustCompile(":(.*?)$") 84 url = reg1.ReplaceAllString(url, "{$1}/") 85 url = reg2.ReplaceAllString(url, "{$1}") 86 87 if len(url) > 1 && url[0] == '/' && url[1] == '/' { 88 url = url[1:] 89 } 90 91 getHandleFunc(ch.app, strings.ToUpper(method))(url, func(w http.ResponseWriter, r *http.Request) { 92 93 if r.URL.Path[len(r.URL.Path)-1] == '/' { 94 r.URL.Path = r.URL.Path[:len(r.URL.Path)-1] 95 } 96 97 ctx := context.NewContext(r) 98 99 params := chi.RouteContext(r.Context()).URLParams 100 101 for i := 0; i < len(params.Values); i++ { 102 if r.URL.RawQuery == "" { 103 r.URL.RawQuery += strings.ReplaceAll(params.Keys[i], ":", "") + "=" + params.Values[i] 104 } else { 105 r.URL.RawQuery += "&" + strings.ReplaceAll(params.Keys[i], ":", "") + "=" + params.Values[i] 106 } 107 } 108 109 ctx.SetHandlers(handlers).Next() 110 for key, head := range ctx.Response.Header { 111 w.Header().Set(key, head[0]) 112 } 113 if ctx.Response.Body != nil { 114 buf := new(bytes.Buffer) 115 _, _ = buf.ReadFrom(ctx.Response.Body) 116 w.WriteHeader(ctx.Response.StatusCode) 117 _, _ = w.Write(buf.Bytes()) 118 } else { 119 w.WriteHeader(ctx.Response.StatusCode) 120 } 121 }) 122 } 123 124 // HandleFun is type of route methods of chi. 125 type HandleFun func(pattern string, handlerFn http.HandlerFunc) 126 127 func getHandleFunc(eng *chi.Mux, method string) HandleFun { 128 switch method { 129 case "GET": 130 return eng.Get 131 case "POST": 132 return eng.Post 133 case "PUT": 134 return eng.Put 135 case "DELETE": 136 return eng.Delete 137 case "HEAD": 138 return eng.Head 139 case "OPTIONS": 140 return eng.Options 141 case "PATCH": 142 return eng.Patch 143 default: 144 panic("wrong method") 145 } 146 } 147 148 // Context wraps the Request and Response object of Chi. 149 type Context struct { 150 Request *http.Request 151 Response http.ResponseWriter 152 } 153 154 // SetContext implements the method Adapter.SetContext. 155 func (*Chi) SetContext(contextInterface interface{}) adapter.WebFrameWork { 156 var ( 157 ctx Context 158 ok bool 159 ) 160 if ctx, ok = contextInterface.(Context); !ok { 161 panic("chi adapter SetContext: wrong parameter") 162 } 163 return &Chi{ctx: ctx} 164 } 165 166 // Name implements the method Adapter.Name. 167 func (*Chi) Name() string { 168 return "chi" 169 } 170 171 // Redirect implements the method Adapter.Redirect. 172 func (ch *Chi) Redirect() { 173 http.Redirect(ch.ctx.Response, ch.ctx.Request, cfg.Url(cfg.GetLoginUrl()), http.StatusFound) 174 } 175 176 // SetContentType implements the method Adapter.SetContentType. 177 func (ch *Chi) SetContentType() { 178 ch.ctx.Response.Header().Set("Content-Type", ch.HTMLContentType()) 179 } 180 181 // Write implements the method Adapter.Write. 182 func (ch *Chi) Write(body []byte) { 183 ch.ctx.Response.WriteHeader(http.StatusOK) 184 _, _ = ch.ctx.Response.Write(body) 185 } 186 187 // GetCookie implements the method Adapter.GetCookie. 188 func (ch *Chi) GetCookie() (string, error) { 189 cookie, err := ch.ctx.Request.Cookie(ch.CookieKey()) 190 if err != nil { 191 return "", err 192 } 193 return cookie.Value, err 194 } 195 196 // Lang implements the method Adapter.Lang. 197 func (ch *Chi) Lang() string { 198 return ch.ctx.Request.URL.Query().Get("__ga_lang") 199 } 200 201 // Path implements the method Adapter.Path. 202 func (ch *Chi) Path() string { 203 return ch.ctx.Request.URL.Path 204 } 205 206 // Method implements the method Adapter.Method. 207 func (ch *Chi) Method() string { 208 return ch.ctx.Request.Method 209 } 210 211 // FormParam implements the method Adapter.FormParam. 212 func (ch *Chi) FormParam() url.Values { 213 _ = ch.ctx.Request.ParseMultipartForm(32 << 20) 214 return ch.ctx.Request.PostForm 215 } 216 217 // IsPjax implements the method Adapter.IsPjax. 218 func (ch *Chi) IsPjax() bool { 219 return ch.ctx.Request.Header.Get(constant.PjaxHeader) == "true" 220 } 221 222 // Query implements the method Adapter.Query. 223 func (ch *Chi) Query() url.Values { 224 return ch.ctx.Request.URL.Query() 225 }