166 lines
3.8 KiB
Go
166 lines
3.8 KiB
Go
package runner
|
|
|
|
import (
|
|
"Moonshark/router"
|
|
"Moonshark/runner/lualibs"
|
|
"Moonshark/sessions"
|
|
"Moonshark/utils"
|
|
"sync"
|
|
|
|
"github.com/valyala/fasthttp"
|
|
)
|
|
|
|
// A prebuilt, ready-to-go context for HTTP requests to the runner.
|
|
type HTTPContext struct {
|
|
Method []byte
|
|
Path []byte
|
|
Host []byte
|
|
Headers map[string]any
|
|
Cookies map[string]string
|
|
Query map[string]string
|
|
Params map[string]any
|
|
Form map[string]any
|
|
Session map[string]any
|
|
Env map[string]any
|
|
Values map[string]any // Extra context vars just in case
|
|
}
|
|
|
|
// HTTP context pool to reduce allocations
|
|
var httpContextPool = sync.Pool{
|
|
New: func() any {
|
|
return &HTTPContext{
|
|
Headers: make(map[string]any, 16),
|
|
Cookies: make(map[string]string, 8),
|
|
Query: make(map[string]string, 8),
|
|
Params: make(map[string]any, 4),
|
|
Form: make(map[string]any, 8),
|
|
Session: make(map[string]any, 4),
|
|
Env: make(map[string]any, 16),
|
|
Values: make(map[string]any, 32),
|
|
}
|
|
},
|
|
}
|
|
|
|
// Get a clean HTTP context from the pool and build it up with an HTTP request, router params and session data
|
|
func NewHTTPContext(httpCtx *fasthttp.RequestCtx, params *router.Params, session *sessions.Session) *HTTPContext {
|
|
ctx := httpContextPool.Get().(*HTTPContext)
|
|
|
|
// Extract basic HTTP info
|
|
ctx.Method = httpCtx.Method()
|
|
ctx.Path = httpCtx.Path()
|
|
ctx.Host = httpCtx.Host()
|
|
|
|
// Extract headers
|
|
httpCtx.Request.Header.VisitAll(func(key, value []byte) {
|
|
ctx.Headers[string(key)] = string(value)
|
|
})
|
|
|
|
// Extract cookies
|
|
httpCtx.Request.Header.VisitAllCookie(func(key, value []byte) {
|
|
ctx.Cookies[string(key)] = string(value)
|
|
})
|
|
|
|
// Extract query params
|
|
httpCtx.QueryArgs().VisitAll(func(key, value []byte) {
|
|
ctx.Query[string(key)] = string(value)
|
|
})
|
|
|
|
// Extract route parameters
|
|
if params != nil {
|
|
for i := 0; i < min(len(params.Keys), len(params.Values)); i++ {
|
|
ctx.Params[params.Keys[i]] = params.Values[i]
|
|
}
|
|
}
|
|
|
|
// Extract form data if present
|
|
if httpCtx.IsPost() || httpCtx.IsPut() || httpCtx.IsPatch() {
|
|
if form, err := utils.ParseForm(httpCtx); err == nil {
|
|
for k, v := range form {
|
|
ctx.Form[k] = v
|
|
}
|
|
}
|
|
}
|
|
|
|
// Extract session data
|
|
session.AdvanceFlash()
|
|
ctx.Session["id"] = session.ID
|
|
if session.IsEmpty() {
|
|
ctx.Session["data"] = emptyMap
|
|
ctx.Session["flash"] = emptyMap
|
|
} else {
|
|
ctx.Session["data"] = session.GetAll()
|
|
ctx.Session["flash"] = session.GetAllFlash()
|
|
}
|
|
|
|
// Add environment vars
|
|
if envMgr := lualibs.GetGlobalEnvManager(); envMgr != nil {
|
|
for k, v := range envMgr.GetAll() {
|
|
ctx.Env[k] = v
|
|
}
|
|
}
|
|
|
|
return ctx
|
|
}
|
|
|
|
// Clear out all the request data from the context and give it back to the pool. Keeps the contexts and inner maps
|
|
// allocated to prevent GC churn.
|
|
func (c *HTTPContext) Release() {
|
|
for k := range c.Headers {
|
|
delete(c.Headers, k)
|
|
}
|
|
for k := range c.Cookies {
|
|
delete(c.Cookies, k)
|
|
}
|
|
for k := range c.Query {
|
|
delete(c.Query, k)
|
|
}
|
|
for k := range c.Params {
|
|
delete(c.Params, k)
|
|
}
|
|
for k := range c.Form {
|
|
delete(c.Form, k)
|
|
}
|
|
for k := range c.Session {
|
|
delete(c.Session, k)
|
|
}
|
|
for k := range c.Env {
|
|
delete(c.Env, k)
|
|
}
|
|
for k := range c.Values {
|
|
delete(c.Values, k)
|
|
}
|
|
|
|
c.Method = nil
|
|
c.Path = nil
|
|
c.Host = nil
|
|
|
|
httpContextPool.Put(c)
|
|
}
|
|
|
|
// Add a value to the extras map
|
|
func (c *HTTPContext) Set(key string, value any) {
|
|
c.Values[key] = value
|
|
}
|
|
|
|
// Get a value from the extras map
|
|
func (c *HTTPContext) Get(key string) any {
|
|
return c.Values[key]
|
|
}
|
|
|
|
// Returns a representation of the context ready for Lua
|
|
func (c *HTTPContext) ToMap() map[string]any {
|
|
return map[string]any{
|
|
"method": string(c.Method),
|
|
"path": string(c.Path),
|
|
"host": string(c.Host),
|
|
"headers": c.Headers,
|
|
"cookies": c.Cookies,
|
|
"query": c.Query,
|
|
"params": c.Params,
|
|
"form": c.Form,
|
|
"session": c.Session,
|
|
"env": c.Env,
|
|
"values": c.Values,
|
|
}
|
|
}
|