Moonshark/runner/httpContext.go

139 lines
3.4 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 {
Values map[string]any // Contains all context data for Lua
// Separate maps for efficient access during context building
headers map[string]string
cookies map[string]string
query map[string]string
params map[string]string
form map[string]any
session map[string]any
env map[string]any
}
// HTTP context pool to reduce allocations
var httpContextPool = sync.Pool{
New: func() any {
return &HTTPContext{
Values: make(map[string]any, 32),
headers: make(map[string]string, 16),
cookies: make(map[string]string, 8),
query: make(map[string]string, 8),
params: make(map[string]string, 4),
form: make(map[string]any, 8),
session: make(map[string]any, 4),
env: make(map[string]any, 16),
}
},
}
// 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 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 := range min(len(params.Keys), len(params.Values)) {
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
}
}
// Populate Values with all context data
ctx.Values["method"] = string(httpCtx.Method())
ctx.Values["path"] = string(httpCtx.Path())
ctx.Values["host"] = string(httpCtx.Host())
ctx.Values["headers"] = ctx.headers
ctx.Values["cookies"] = ctx.cookies
ctx.Values["query"] = ctx.query
ctx.Values["params"] = ctx.params
ctx.Values["form"] = ctx.form
ctx.Values["session"] = ctx.session
ctx.Values["env"] = ctx.env
return ctx
}
// Clear out all the request data from the context and give it back to the pool.
func (c *HTTPContext) Release() {
clear(c.Values)
clear(c.headers)
clear(c.cookies)
clear(c.query)
clear(c.params)
clear(c.form)
clear(c.session)
clear(c.env)
httpContextPool.Put(c)
}
// Add a value to the extras section
func (c *HTTPContext) Set(key string, value any) {
c.Values[key] = value
}
// Get a value from the context
func (c *HTTPContext) Get(key string) any {
return c.Values[key]
}
// Returns the Values map directly - zero overhead
func (c *HTTPContext) ToMap() map[string]any {
return c.Values
}