lolly/internal/lua/context.go
xfy 7a66e350f0 feat(lua): 添加 Lua 脚本嵌入支持
- 基于 gopher-lua 实现类似 OpenResty 的脚本嵌入能力
- LuaEngine: server 级单 LState + 请求级临时协程
- LuaContext: 请求上下文,变量存储和阶段管理
- LuaCoroutine: 沙箱隔离,Yield/Resume 循环,执行超时
- CodeCache: 字节码缓存,LRU 淘汰 + TTL 过期
- 新增 testify 用于测试断言

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 14:19:03 +08:00

126 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package lua 提供 Lua 脚本嵌入能力
package lua
import (
"github.com/valyala/fasthttp"
)
// LuaContext 请求级 Lua 上下文
type LuaContext struct {
// 引擎引用
Engine *LuaEngine
// 协程
Coroutine *LuaCoroutine
// HTTP 请求上下文
RequestCtx *fasthttp.RequestCtx
// 当前阶段
Phase Phase
// 变量存储ngx.var 实现)
Variables map[string]string
// 输出缓冲
OutputBuffer []byte
// 是否已退出
Exited bool
}
// NewContext 创建请求上下文
func NewContext(engine *LuaEngine, req *fasthttp.RequestCtx) *LuaContext {
return &LuaContext{
Engine: engine,
RequestCtx: req,
Variables: make(map[string]string),
Phase: PhaseInit,
}
}
// InitCoroutine 初始化协程
func (c *LuaContext) InitCoroutine() error {
coro, err := c.Engine.NewCoroutine(c.RequestCtx)
if err != nil {
return err
}
c.Coroutine = coro
return c.Coroutine.SetupSandbox()
}
// Execute 执行 Lua 脚本
func (c *LuaContext) Execute(script string) error {
if c.Coroutine == nil {
if err := c.InitCoroutine(); err != nil {
return err
}
}
return c.Coroutine.Execute(script)
}
// ExecuteFile 执行文件脚本
func (c *LuaContext) ExecuteFile(path string) error {
if c.Coroutine == nil {
if err := c.InitCoroutine(); err != nil {
return err
}
}
return c.Coroutine.ExecuteFile(path)
}
// SetPhase 设置当前阶段
func (c *LuaContext) SetPhase(phase Phase) {
c.Phase = phase
}
// GetPhase 获取当前阶段
func (c *LuaContext) GetPhase() Phase {
return c.Phase
}
// GetVariable 获取变量
func (c *LuaContext) GetVariable(name string) (string, bool) {
val, ok := c.Variables[name]
return val, ok
}
// SetVariable 设置变量
func (c *LuaContext) SetVariable(name, value string) {
c.Variables[name] = value
}
// Write 输出内容
func (c *LuaContext) Write(data []byte) {
c.OutputBuffer = append(c.OutputBuffer, data...)
}
// Say 输出内容并换行
func (c *LuaContext) Say(data string) {
c.OutputBuffer = append(c.OutputBuffer, data...)
c.OutputBuffer = append(c.OutputBuffer, '\n')
}
// Exit 退出请求处理
func (c *LuaContext) Exit(code int) {
c.Exited = true
c.RequestCtx.SetStatusCode(code)
}
// Release 释放资源
func (c *LuaContext) Release() {
if c.Coroutine != nil {
c.Coroutine.Close()
c.Coroutine = nil
}
c.Variables = nil
c.OutputBuffer = nil
}
// FlushOutput 刷新输出到响应
func (c *LuaContext) FlushOutput() {
if len(c.OutputBuffer) > 0 && c.RequestCtx != nil {
c.RequestCtx.Write(c.OutputBuffer)
c.OutputBuffer = c.OutputBuffer[:0]
}
}