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 }