139 lines
3.3 KiB
Go
139 lines
3.3 KiB
Go
package runner
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/valyala/bytebufferpool"
|
|
"github.com/valyala/fasthttp"
|
|
)
|
|
|
|
// Context represents execution context for a Lua script
|
|
type Context struct {
|
|
// Values stores any context values (route params, HTTP request info, etc.)
|
|
Values map[string]any
|
|
|
|
// FastHTTP context if this was created from an HTTP request
|
|
RequestCtx *fasthttp.RequestCtx
|
|
|
|
// Session information
|
|
SessionID string
|
|
SessionData map[string]any
|
|
|
|
// Buffer for efficient string operations
|
|
buffer *bytebufferpool.ByteBuffer
|
|
}
|
|
|
|
// Context pool to reduce allocations
|
|
var contextPool = sync.Pool{
|
|
New: func() any {
|
|
return &Context{
|
|
Values: make(map[string]any, 16),
|
|
SessionData: make(map[string]any, 8),
|
|
}
|
|
},
|
|
}
|
|
|
|
// NewContext creates a new context, potentially reusing one from the pool
|
|
func NewContext() *Context {
|
|
return contextPool.Get().(*Context)
|
|
}
|
|
|
|
// NewHTTPContext creates a new context from a fasthttp RequestCtx
|
|
func NewHTTPContext(requestCtx *fasthttp.RequestCtx) *Context {
|
|
ctx := NewContext()
|
|
ctx.RequestCtx = requestCtx
|
|
|
|
// Extract common HTTP values that Lua might need
|
|
if requestCtx != nil {
|
|
ctx.Values["_request_method"] = string(requestCtx.Method())
|
|
ctx.Values["_request_path"] = string(requestCtx.Path())
|
|
ctx.Values["_request_url"] = string(requestCtx.RequestURI())
|
|
|
|
// Extract cookies
|
|
cookies := make(map[string]any)
|
|
requestCtx.Request.Header.VisitAllCookie(func(key, value []byte) {
|
|
cookies[string(key)] = string(value)
|
|
})
|
|
ctx.Values["_request_cookies"] = cookies
|
|
|
|
// Extract query params
|
|
query := make(map[string]any)
|
|
requestCtx.QueryArgs().VisitAll(func(key, value []byte) {
|
|
query[string(key)] = string(value)
|
|
})
|
|
ctx.Values["_request_query"] = query
|
|
|
|
// Extract form data if present
|
|
if requestCtx.IsPost() || requestCtx.IsPut() {
|
|
form := make(map[string]any)
|
|
requestCtx.PostArgs().VisitAll(func(key, value []byte) {
|
|
form[string(key)] = string(value)
|
|
})
|
|
ctx.Values["_request_form"] = form
|
|
}
|
|
|
|
// Extract headers
|
|
headers := make(map[string]any)
|
|
requestCtx.Request.Header.VisitAll(func(key, value []byte) {
|
|
headers[string(key)] = string(value)
|
|
})
|
|
ctx.Values["_request_headers"] = headers
|
|
}
|
|
|
|
return ctx
|
|
}
|
|
|
|
// Release returns the context to the pool after clearing its values
|
|
func (c *Context) Release() {
|
|
// Clear all values to prevent data leakage
|
|
for k := range c.Values {
|
|
delete(c.Values, k)
|
|
}
|
|
|
|
for k := range c.SessionData {
|
|
delete(c.SessionData, k)
|
|
}
|
|
|
|
// Reset session info
|
|
c.SessionID = ""
|
|
|
|
// Reset request context
|
|
c.RequestCtx = nil
|
|
|
|
// Return buffer to pool if we have one
|
|
if c.buffer != nil {
|
|
bytebufferpool.Put(c.buffer)
|
|
c.buffer = nil
|
|
}
|
|
|
|
contextPool.Put(c)
|
|
}
|
|
|
|
// GetBuffer returns a byte buffer for efficient string operations
|
|
func (c *Context) GetBuffer() *bytebufferpool.ByteBuffer {
|
|
if c.buffer == nil {
|
|
c.buffer = bytebufferpool.Get()
|
|
}
|
|
return c.buffer
|
|
}
|
|
|
|
// Set adds a value to the context
|
|
func (c *Context) Set(key string, value any) {
|
|
c.Values[key] = value
|
|
}
|
|
|
|
// Get retrieves a value from the context
|
|
func (c *Context) Get(key string) any {
|
|
return c.Values[key]
|
|
}
|
|
|
|
// SetSession sets a session data value
|
|
func (c *Context) SetSession(key string, value any) {
|
|
c.SessionData[key] = value
|
|
}
|
|
|
|
// GetSession retrieves a session data value
|
|
func (c *Context) GetSession(key string) any {
|
|
return c.SessionData[key]
|
|
}
|