script_engine

package module
v0.0.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 9, 2026 License: MIT Imports: 7 Imported by: 2

README

Go Scripts · 多语言嵌入式脚本引擎框架

License Go Version Go Reference

为 Go 应用打造的一站式多语言脚本引擎框架

让宿主程序以统一接口无缝嵌入 9 种脚本语言,以扩展运行时行为、实现热插拔逻辑与快速原型开发

中文 · English · 日本語


项目亮点

  • 九大引擎,能力接口:Lua、JavaScript、Python (gpython)、Go (Yaegi)、WebAssembly (Wazero)、CEL、Expr、Starlark、TCL —— 按能力拆分的小接口(ScriptEngine / ScriptLoader / ScriptExecutor / ...),完整引擎聚合为 Engine,轻量引擎按需实现
  • 零 CGO 依赖:全部引擎均为纯 Go 实现,跨平台编译开箱即用,容器化部署无额外开销
  • 生产级引擎池:内置固定大小池 (EnginePool) 与自动扩容池 (AutoGrowEnginePool),支持高并发脚本执行
  • 多租户引擎管理Manager 组件提供命名空间隔离的多引擎生命周期管理
  • 多源脚本加载:File、Memory、S3、etcd、Consul、Redis、HTTP、MultiSource(Fallback / FirstOK 双策略聚合)
  • 热更新:实现 ScriptWatcher 的引擎支持 StartWatch / StopWatch,脚本变更自动重载,零停机发布
  • 宿主互操作:全局变量注入、Go 函数注册、模块注册、脚本函数回调,双向数据桥接
  • 线程安全:双锁模式 (RWMutex + execMutex) + Context 取消机制,保障并发场景下的数据一致性

什么是 Go Scripts?

Go Scripts 是一个 可扩展的嵌入式脚本引擎框架,为 Go 应用程序提供统一的脚本执行层。它解决了以下核心问题:

  • 语言碎片化:不同场景需要不同脚本语言(规则引擎用 CEL、业务逻辑用 Python、快速验证用 JavaScript),但每种语言的嵌入方式各异
  • 生命周期管理:脚本引擎的初始化、预热、池化、并发控制、优雅关闭,需要大量样板代码
  • 脚本来源多样化:本地文件、对象存储、配置中心、内存注入 —— 不同来源需要不同的加载策略
  • 热更新需求:线上脚本逻辑需要不停机更新,传统的"编译-部署"循环无法满足快速迭代

Go Scripts 的设计哲学是:一套接口,多语言支持;一个框架,覆盖从开发到生产的全生命周期


脚本引擎

引擎 类型常量 底层库 语言版本 适用场景
Lua LuaType gopher-lua Lua 5.1 游戏脚本、配置逻辑、嵌入式扩展
JavaScript JavaScriptType goja ES5.1+ (ES6 子集) 前端复用、规则引擎、快速原型
Python GPythonType gpython Python 3.4 子集 数据处理、运维脚本、算法验证
Go YaegiType Yaegi Go 1.x 动态插件、DevOps 工具链
WebAssembly WazeroType wazero WASM 1.0 高性能沙箱、跨语言模块复用
CEL CELType cel-go CEL spec 策略引擎、权限规则、条件判断
Expr ExprType expr Expr DSL 业务表达式、模板引擎、数据筛选
Starlark StarlarkType starlark-go Starlark (Python 方言) 构建工具、安全脚本、Bazel 规则
TCL TclType modernc/tcl TCL 8.6 传统系统兼容、网络设备脚本

系统架构

graph TB
    subgraph "应用层"
        APP["宿主应用<br/>Go Application"]
    end

    subgraph "框架核心"
        FACTORY["Factory<br/>工厂注册表"]
        MGR["Manager<br/>多引擎管理"]
        POOL["EnginePool / AutoGrowEnginePool<br/>引擎池"]
        IFACE["Engine Interface<br/>统一接口"]
    end

    subgraph "脚本引擎 (9 种)"
        LUA["Lua"]
        JS["JavaScript"]
        PY["gpython"]
        YG["Yaegi"]
        WZ["Wazero"]
        CEL["CEL"]
        EXPR["Expr"]
        ST["Starlark"]
        TCL["TCL"]
    end

    subgraph "脚本来源 (7 种)"
        FILE["File"]
        MEM["Memory"]
        S3["S3"]
        ETCD["etcd"]
        CONSUL["Consul"]
        REDIS["Redis"]
        HTTP["HTTP"]
        MULTI["MultiSource<br/>聚合 / Fallback"]
    end

    APP --> FACTORY
    APP --> MGR
    APP --> POOL
    FACTORY --> IFACE
    MGR --> IFACE
    POOL --> IFACE
    IFACE --> LUA & JS & PY & YG & WZ & CEL & EXPR & ST & TCL
    IFACE --> FILE & MEM & S3 & ETCD & CONSUL & REDIS & HTTP
    FILE & MEM & S3 & ETCD & CONSUL & REDIS & HTTP --> MULTI

接口架构

Go Scripts 采用接口隔离原则 (ISP) 设计引擎接口,与 source 模块的 Reader / Watcher / ReadWatcher 分离哲学一致:

graph TB
    subgraph "核心接口(所有引擎必须实现)"
        SE["ScriptEngine<br/>GetType / Init / Close / IsInitialized<br/>GetLastError / ClearError"]
    end

    subgraph "能力接口(按需实现)"
        SL["ScriptLoader"]
        SX["ScriptExecutor"]
        GA["GlobalAccessor"]
        FR["FunctionRegistrar"]
        MR["ModuleRegistrar"]
        SW["ScriptWatcher"]
    end

    subgraph "聚合接口"
        ENG["Engine = ScriptEngine + 全部能力接口"]
    end

    subgraph "完整实现"
        LUA["Lua ✅"]
        JS["JavaScript ✅"]
    end

    subgraph "轻量实现(示例)"
        CEL["CEL<br/>ScriptEngine + ScriptExecutor"]
        EXPR["Expr<br/>ScriptEngine + ScriptExecutor"]
    end

    SE --> ENG
    SL & SX & GA & FR & MR & SW --> ENG
    ENG --> LUA & JS
    SE --> CEL & EXPR
    SX --> CEL & EXPR
接口 方法 说明
ScriptEngine GetType / Init / Close / IsInitialized / GetLastError / ClearError 核心:所有引擎必须实现
ScriptLoader SetSource / GetSource / Load / LoadMulti / LoadString 能力:源驱动脚本加载
ScriptExecutor Execute / ExecuteFromKey / ExecuteFromKeys / ExecuteString 能力:脚本执行
GlobalAccessor RegisterGlobal / GetGlobal 能力:全局变量读写
FunctionRegistrar RegisterFunction / CallFunction 能力:函数注册与调用
ModuleRegistrar RegisterModule 可选:模块系统
ScriptWatcher StartWatch / StopWatch 可选:热更新监听
Engine (聚合上述全部) 聚合:Lua / JavaScript 等完整引擎

调用方通过 AsLoader(eng)AsWatcher(eng) 等辅助函数或类型断言检测引擎是否支持特定能力。


核心功能

引擎管理
功能 说明
工厂模式 NewScriptEngine(typ) 按类型创建引擎,通过 init() 自动注册
引擎管理器 Manager 支持按名称注册、查找、批量初始化/关闭
引擎池 EnginePool(固定大小)+ AutoGrowEnginePool(自动扩容)
生命周期 InitLoad / ExecuteClose,状态机式管理
脚本加载与执行
功能 说明
多源加载 File、Memory、S3、etcd、Consul、Redis、HTTP 七种来源
聚合策略 MultiSource 支持 Fallback(顺序回退)和 FirstOK(并发择快)
执行模式 Execute(批量执行)、ExecuteFromKey(按 key 加载+执行)、ExecuteString(内联执行)
全局变量 RegisterGlobal / GetGlobal 宿主与脚本双向变量桥接
函数互调 RegisterFunction(Go → 脚本)、CallFunction(脚本 → Go)
模块注册 RegisterModule 注册自定义模块供脚本 require / import
热更新
功能 说明
变更监听 StartWatch / StopWatch 通过 Source 的 Watcher 接口监听变更
自动重载 脚本变更后自动重新加载并编译,无需重启
事件驱动 etcd 原生 Watch、File mtime 轮询、S3 ETag 比对、Memory 内嵌通知

技术栈

层级 技术 说明
语言 Go 1.24+ 高性能编译型语言
架构模式 接口驱动 + 工厂模式 可扩展、可替换
并发模型 goroutine + channel + sync 双锁模式保障线程安全
热更新 Watcher 接口 + context.CancelFunc 事件驱动 + 资源回收
测试覆盖 testify + httptest + 700+ test cases 单元测试 + 集成测试

项目结构

go-scripts/
├── engine.go                     # 能力接口 + Engine 聚合接口 + 辅助函数
├── factory.go                    # 工厂注册表
├── manager.go                    # 多引擎管理器
├── engine_pool.go                # 固定大小引擎池
├── engine_pool_autogrow.go       # 自动扩容引擎池
├── types.go                      # 类型常量定义
├── source/                       # 脚本来源模块
│   ├── source.go                 # Reader / Watcher / ReadWatcher 接口
│   ├── file.go                   # 本地文件源
│   ├── fs.go                     # io/fs.FS 源 (embed / zip)
│   ├── memory.go                 # 内存源
│   ├── multiple.go               # 多源聚合 (Fallback / FirstOK)
│   ├── transform.go              # 解密/解压/过滤中间件
│   ├── cached.go                 # 缓存层 (TTL + Watch 自动失效)
│   ├── s3/                       # Amazon S3 / 兼容对象存储
│   ├── etcd/                     # etcd KV
│   ├── consul/                   # Consul KV
│   ├── redis/                    # Redis
│   ├── http/                     # HTTP 远程拉取
│   ├── git/                      # Git 仓库 (go-git/v6)
│   └── database/                 # SQL 数据库 (database/sql)
├── lua/                          # Lua 引擎 (gopher-lua)
├── javascript/                   # JavaScript 引擎 (goja)
├── gpython/                      # Python 引擎 (gpython)
├── yaegi/                        # Go 引擎 (Yaegi)
├── wazero/                       # WebAssembly 引擎 (wazero)
├── cel/                          # CEL 表达式引擎 (cel-go)
├── expr/                         # Expr 表达式引擎 (expr-lang)
├── starlark/                     # Starlark 引擎 (starlark-go)
└── tcl/                          # TCL 引擎 (modernc/tcl)

快速开始

安装
go get github.com/tx7do/go-scripts
基础用法
package main

import (
    "context"
    "fmt"
    "log"

    scriptEngine "github.com/tx7do/go-scripts"
    _ "github.com/tx7do/go-scripts/javascript" // 注册 JavaScript 引擎
)

func main() {
    // 1. 创建引擎实例
    eng, err := scriptEngine.NewScriptEngine(scriptEngine.JavaScriptType)
    if err != nil {
        log.Fatal(err)
    }
    defer eng.Close()

    // 2. 初始化
    ctx := context.Background()
    if err := eng.Init(ctx); err != nil {
        log.Fatal(err)
    }

    // 3. 注入宿主变量
    _ = eng.RegisterGlobal("name", "world")

    // 4. 注册宿主函数
    _ = eng.RegisterFunction("greet", func(name string) string {
        return fmt.Sprintf("Hello, %s!", name)
    })

    // 5. 执行脚本
    result, err := eng.ExecuteString(ctx, "hello.js", `greet(name)`)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(result) // Hello, world!
}
引擎池(生产推荐)
// 固定大小引擎池(8 实例)
pool, err := scriptEngine.NewEnginePool(8, scriptEngine.LuaType)

// 或:自动扩容池(初始 2,上限 16)
pool, err := scriptEngine.NewAutoGrowEnginePool(2, 16, scriptEngine.LuaType)
if err != nil {
    log.Fatal(err)
}
defer pool.Close()

// 注入宿主函数(注:仅作用于被 Acquire 的实例)
_ = pool.RegisterFunction("calc", func(a, b int) int { return a + b })

// 执行脚本
result, _ := pool.ExecuteString(ctx, "calc.lua", `return calc(10, 20)`)
配合 ScriptSource
// 从本地文件加载
src := source.NewFileSource()
eng.SetSource(src)

// 从文件执行
result, _ := eng.ExecuteFromKey(ctx, "/path/to/script.lua")

// S3 + Memory Fallback
s3Src, _ := s3source.New(ctx, "my-bucket", s3source.WithRegion("us-east-1"))
memSrc := source.NewMemSource()
memSrc.Set("backup.lua", `print("fallback")`)

multi, _ := source.NewFallbackSource(s3Src, memSrc)
eng.SetSource(multi)
热更新
// 启动监听
if err := eng.StartWatch(ctx, "/path/to/script.lua"); err != nil {
    log.Fatal(err)
}
// 文件变更时自动重载,无需手动干预

// 停止监听
_ = eng.StopWatch("/path/to/script.lua")

测试

# 运行所有子模块测试
cd lua && go test -v ./...
cd javascript && go test -v ./...
cd cel && go test -v ./...
cd expr && go test -v ./...
cd starlark && go test -v ./...
cd gpython && go test -v ./...
cd yaegi && go test -v ./...
cd wazero && go test -v ./...
cd tcl && go test -v ./...

测试覆盖:

类别 用例
生命周期 Init / Close / IsInitialized
脚本加载 Load / LoadMulti / LoadString
脚本执行 Execute / ExecuteFromKey / ExecuteFromKeys / ExecuteString
宿主互操作 RegisterGlobal / GetGlobal / RegisterFunction / CallFunction / RegisterModule
热更新 StartWatch / StopWatch
并发压测 50+ goroutine × 200 loop 并发执行
Source 集成 FileSource 端到端 / MemSource / MultiSource
引擎池 Acquire / Release / InitAll / Close

相关文档

脚本引擎
脚本来源
外部资源

License

MIT License

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrCapabilityNotSupported = errors.New("script engine: capability not supported by this engine type")

ErrCapabilityNotSupported is returned when an engine does not implement an optional capability interface (e.g. ModuleRegistrar, ScriptWatcher).

Callers that receive this error should gracefully degrade instead of treating it as a fatal failure.

Functions

func Register

func Register(typ Type, f FactoryFunc) error

Register registers a FactoryFunc for the given Type. Returns an error if a factory for typ is already registered.

func SetLogger added in v0.0.6

func SetLogger(l Logger)

SetLogger sets the package-level Logger used by all engines, pools and submodules. Pass nil to revert to the silent nopLogger.

SetLogger is safe to call concurrently with log calls; callers that want to mutate the logger without races should hold their own coordination.

func Unregister

func Unregister(typ Type) bool

Unregister removes the factory registered for typ. It returns true if a factory was removed.

Types

type AutoGrowEnginePool added in v0.0.2

type AutoGrowEnginePool struct {
	// contains filtered or unexported fields
}

AutoGrowEnginePool is an Engine pool that can grow on demand up to a configured maximum. Idle instances are reused; when none is available and the cap has not been reached, a new Engine is created on the fly.

func NewAutoGrowEnginePool added in v0.0.2

func NewAutoGrowEnginePool(initialSize, maxSize int, typ Type) (*AutoGrowEnginePool, error)

NewAutoGrowEnginePool creates a pool that can grow on demand.

  • initialSize: number of Engines to create eagerly (>= 0)
  • maxSize: upper bound on instance count (must be >= initialSize and >= 1)
  • typ: selects the registered factory used to build each Engine

func (*AutoGrowEnginePool) Acquire added in v0.0.2

func (p *AutoGrowEnginePool) Acquire() (Engine, error)

Acquire returns an Engine from the pool.

  • If an idle instance is available, it is returned immediately.
  • Otherwise, if total < max, a new instance is created and returned.
  • Otherwise the call blocks until an instance is released.

func (*AutoGrowEnginePool) CallFunction added in v0.0.2

func (p *AutoGrowEnginePool) CallFunction(ctx context.Context, name string, args ...any) (any, error)

CallFunction invokes the named script function on an acquired Engine.

func (*AutoGrowEnginePool) ClearError added in v0.0.2

func (p *AutoGrowEnginePool) ClearError()

ClearError clears the last error on an acquired Engine.

func (*AutoGrowEnginePool) Close added in v0.0.2

func (p *AutoGrowEnginePool) Close() error

Close closes the pool and destroys every currently idle instance. Engines that are still borrowed must be Closed by their callers (or will be Closed when eventually released).

func (*AutoGrowEnginePool) Execute added in v0.0.2

func (p *AutoGrowEnginePool) Execute(ctx context.Context) (any, error)

Execute runs every previously-loaded script on an acquired Engine and returns the combined result.

func (*AutoGrowEnginePool) ExecuteFromKey added in v0.0.6

func (p *AutoGrowEnginePool) ExecuteFromKey(ctx context.Context, key string) (any, error)

ExecuteFromKey loads (via the bound Source) and immediately runs the script identified by key on an acquired Engine.

func (*AutoGrowEnginePool) ExecuteFromKeys added in v0.0.6

func (p *AutoGrowEnginePool) ExecuteFromKeys(ctx context.Context, keys []string) ([]any, error)

ExecuteFromKeys is the multi-key variant of ExecuteFromKey; results are returned in the same order as keys.

func (*AutoGrowEnginePool) ExecuteString added in v0.0.2

func (p *AutoGrowEnginePool) ExecuteString(ctx context.Context, name string, code string) (any, error)

ExecuteString compiles and immediately runs the inline script (name+code) on an acquired Engine, bypassing the bound Source.

func (*AutoGrowEnginePool) GetGlobal added in v0.0.2

func (p *AutoGrowEnginePool) GetGlobal(name string) (any, error)

GetGlobal reads a global variable from an acquired Engine.

func (*AutoGrowEnginePool) GetLastError added in v0.0.2

func (p *AutoGrowEnginePool) GetLastError() error

GetLastError returns the last error from an acquired Engine.

func (*AutoGrowEnginePool) GetSource added in v0.0.6

func (p *AutoGrowEnginePool) GetSource() source.Reader

GetSource returns the ScriptSource bound to an acquired Engine (or nil).

func (*AutoGrowEnginePool) Load added in v0.0.6

func (p *AutoGrowEnginePool) Load(ctx context.Context, key string) error

Load loads a single script from the bound Source into an acquired Engine.

func (*AutoGrowEnginePool) LoadMulti added in v0.0.6

func (p *AutoGrowEnginePool) LoadMulti(ctx context.Context, keys []string) error

LoadMulti loads multiple scripts from the bound Source into an acquired Engine.

func (*AutoGrowEnginePool) LoadString added in v0.0.2

func (p *AutoGrowEnginePool) LoadString(ctx context.Context, name string, code string) error

LoadString compiles an inline script (name+code) on an acquired Engine. It does NOT go through the bound Source.

func (*AutoGrowEnginePool) RegisterFunction added in v0.0.2

func (p *AutoGrowEnginePool) RegisterFunction(name string, fn any) error

RegisterFunction registers a host function on an acquired Engine. Note: the registration is LOCAL to that Engine instance.

func (*AutoGrowEnginePool) RegisterGlobal added in v0.0.2

func (p *AutoGrowEnginePool) RegisterGlobal(name string, value any) error

RegisterGlobal registers a global variable on an acquired Engine. Note: the registration is LOCAL to that Engine instance.

func (*AutoGrowEnginePool) RegisterModule added in v0.0.2

func (p *AutoGrowEnginePool) RegisterModule(name string, module any) error

RegisterModule registers a module on an acquired Engine. Note: the registration is LOCAL to that Engine instance.

func (*AutoGrowEnginePool) Release added in v0.0.2

func (p *AutoGrowEnginePool) Release(e Engine)

Release returns an Engine to the pool. If the pool is closed or the channel is full, the Engine is Closed instead and the live counter is decremented.

func (*AutoGrowEnginePool) SetSource added in v0.0.6

func (p *AutoGrowEnginePool) SetSource(source source.Reader)

SetSource binds a ScriptSource on an acquired Engine. Note: the binding is LOCAL to that Engine instance; other engines in the pool are unaffected. See the package-level note above for pool-wide setup.

func (*AutoGrowEnginePool) StartWatch added in v0.0.6

func (p *AutoGrowEnginePool) StartWatch(ctx context.Context, key string) error

StartWatch starts watching the script identified by `key` on an acquired Engine. Note: the watch is LOCAL to that Engine instance.

func (*AutoGrowEnginePool) StopWatch added in v0.0.6

func (p *AutoGrowEnginePool) StopWatch(key string) error

StopWatch stops watching the script identified by `key` on an acquired Engine.

type Engine

Engine is the aggregate interface combining all capability interfaces. Full-featured engines (Lua, JavaScript, ...) implement this.

Lightweight engines (CEL, Expr) may implement only a subset; callers should use the capability helper functions (AsLoader, AsExecutor, ...) or direct type assertions to check for support.

Implementations are expected to be safe for concurrent use of the methods documented as such; see each method's comment for details.

func NewScriptEngine added in v0.0.2

func NewScriptEngine(typ Type) (Engine, error)

NewScriptEngine creates an Engine instance using the factory registered for typ.

type EnginePool added in v0.0.2

type EnginePool struct {
	// contains filtered or unexported fields
}

EnginePool manages a fixed number of independent Engine instances to support concurrent execution. The pool is created via NewEnginePool, which uses the factory registered for typ to instantiate each Engine.

func NewEnginePool added in v0.0.2

func NewEnginePool(size int, typ Type) (*EnginePool, error)

NewEnginePool creates and initializes a pool of size Engines. typ selects the registered factory used to create each Engine.

func (*EnginePool) Acquire added in v0.0.2

func (p *EnginePool) Acquire() (Engine, error)

Acquire takes an Engine out of the pool. It blocks until one becomes available. Returns an error if the pool is already closed.

func (*EnginePool) CallFunction added in v0.0.2

func (p *EnginePool) CallFunction(ctx context.Context, name string, args ...any) (any, error)

CallFunction invokes the named script function on an acquired Engine.

func (*EnginePool) ClearError added in v0.0.2

func (p *EnginePool) ClearError()

ClearError clears the last error on an acquired Engine.

func (*EnginePool) Close added in v0.0.2

func (p *EnginePool) Close() error

Close closes the pool and destroys all pooled Engines.

func (*EnginePool) Execute added in v0.0.2

func (p *EnginePool) Execute(ctx context.Context) (any, error)

Execute runs every previously-loaded script on an acquired Engine and returns the combined result.

func (*EnginePool) ExecuteFromKey added in v0.0.6

func (p *EnginePool) ExecuteFromKey(ctx context.Context, key string) (any, error)

ExecuteFromKey loads (via the bound Source) and immediately runs the script identified by key on an acquired Engine.

func (*EnginePool) ExecuteFromKeys added in v0.0.6

func (p *EnginePool) ExecuteFromKeys(ctx context.Context, keys []string) ([]any, error)

ExecuteFromKeys is the multi-key variant of ExecuteFromKey; results are returned in the same order as keys.

func (*EnginePool) ExecuteString added in v0.0.2

func (p *EnginePool) ExecuteString(ctx context.Context, name string, code string) (any, error)

ExecuteString compiles and immediately runs the inline script (name+code) on an acquired Engine, bypassing the bound Source.

func (*EnginePool) GetGlobal added in v0.0.2

func (p *EnginePool) GetGlobal(name string) (any, error)

GetGlobal reads a global variable from an acquired Engine.

func (*EnginePool) GetLastError added in v0.0.2

func (p *EnginePool) GetLastError() error

GetLastError returns the last error from an acquired Engine.

func (*EnginePool) GetSource added in v0.0.6

func (p *EnginePool) GetSource() source.Reader

GetSource returns the ScriptSource bound to an acquired Engine (or nil).

func (*EnginePool) InitAll added in v0.0.2

func (p *EnginePool) InitAll(ctx context.Context) error

InitAll re-initializes every Engine in the pool. It acquires all instances, calls Init on each, and releases them back.

func (*EnginePool) IsClosed added in v0.0.2

func (p *EnginePool) IsClosed() bool

IsClosed reports whether the pool has been closed.

func (*EnginePool) Load added in v0.0.6

func (p *EnginePool) Load(ctx context.Context, key string) error

Load loads a single script from the bound Source into an acquired Engine.

func (*EnginePool) LoadMulti added in v0.0.6

func (p *EnginePool) LoadMulti(ctx context.Context, keys []string) error

LoadMulti loads multiple scripts from the bound Source into an acquired Engine.

func (*EnginePool) LoadString added in v0.0.2

func (p *EnginePool) LoadString(ctx context.Context, name string, code string) error

LoadString compiles an inline script (name+code) on an acquired Engine. It does NOT go through the bound Source.

func (*EnginePool) RegisterFunction added in v0.0.2

func (p *EnginePool) RegisterFunction(name string, fn any) error

RegisterFunction registers a host function on an acquired Engine. Note: the registration is LOCAL to that Engine instance.

func (*EnginePool) RegisterGlobal added in v0.0.2

func (p *EnginePool) RegisterGlobal(name string, value any) error

RegisterGlobal registers a global variable on an acquired Engine. Note: the registration is LOCAL to that Engine instance.

func (*EnginePool) RegisterModule added in v0.0.2

func (p *EnginePool) RegisterModule(name string, module any) error

RegisterModule registers a module on an acquired Engine. Note: the registration is LOCAL to that Engine instance.

func (*EnginePool) Release added in v0.0.2

func (p *EnginePool) Release(e Engine)

Release returns an Engine to the pool. If the pool is already closed, the Engine is Closed instead.

func (*EnginePool) SetSource added in v0.0.6

func (p *EnginePool) SetSource(source source.Reader)

SetSource binds a ScriptSource on an acquired Engine. Note: the binding is LOCAL to that Engine instance; other engines in the pool are unaffected. See the package-level note above for pool-wide setup.

func (*EnginePool) StartWatch added in v0.0.6

func (p *EnginePool) StartWatch(ctx context.Context, key string) error

StartWatch starts watching the script identified by `key` on an acquired Engine. Note: the watch is LOCAL to that Engine instance.

func (*EnginePool) StopWatch added in v0.0.6

func (p *EnginePool) StopWatch(key string) error

StopWatch stops watching the script identified by `key` on an acquired Engine.

type FactoryFunc

type FactoryFunc func() (Engine, error)

FactoryFunc is the factory function signature used to create an Engine instance.

func GetFactory

func GetFactory(typ Type) (FactoryFunc, bool)

GetFactory returns the FactoryFunc registered for typ and whether it existed.

type FunctionRegistrar added in v0.0.6

type FunctionRegistrar interface {
	// RegisterFunction registers a host function that scripts can call by `name`.
	// The concrete type accepted for `fn` depends on the engine implementation.
	RegisterFunction(name string, fn any) error

	// CallFunction invokes the script-side function registered as `name` with the
	// given arguments and returns its result. ctx can be used to cancel/timeout
	// the call.
	CallFunction(ctx context.Context, name string, args ...any) (any, error)
}

FunctionRegistrar provides host-function registration and script-function invocation.

func AsFunctionRegistrar added in v0.0.6

func AsFunctionRegistrar(e any) FunctionRegistrar

AsFunctionRegistrar returns the FunctionRegistrar capability of e, or nil if unsupported.

type GlobalAccessor added in v0.0.6

type GlobalAccessor interface {
	// RegisterGlobal registers or overwrites a global variable visible to scripts.
	RegisterGlobal(name string, value any) error

	// GetGlobal reads the value of a global variable. Returns an error if the name
	// is undefined.
	GetGlobal(name string) (any, error)
}

GlobalAccessor provides read/write access to global variables visible to scripts.

func AsGlobalAccessor added in v0.0.6

func AsGlobalAccessor(e any) GlobalAccessor

AsGlobalAccessor returns the GlobalAccessor capability of e, or nil if unsupported.

type Logger added in v0.0.6

type Logger interface {
	// Debug logs a message at DEBUG level with optional structured key/value
	// pairs passed as args (alternating keys and values).
	Debug(ctx context.Context, msg string, args ...any)
	// Info logs a message at INFO level.
	Info(ctx context.Context, msg string, args ...any)
	// Warn logs a message at WARN level.
	Warn(ctx context.Context, msg string, args ...any)
	// Error logs a message at ERROR level.
	Error(ctx context.Context, msg string, args ...any)

	// With returns a new Logger instance with the given key-value pairs attached.
	// This is typically used to distinguish modules, e.g., logger.With("module", "goja").
	With(args ...any) Logger
}

Logger is the minimal logging interface used by script_engine internals.

It is deliberately small (4 methods, no WithAttrs/WithGroup) so that any project can adapt its own backend (the stdlib *slog.Logger, zap, zerolog, kratos log, ...) with a few lines of glue code and inject it via SetLogger.

The first argument is always a context, so backends that support it can extract trace ids / request-scoped attributes. Callers that have no context at hand may pass nil.

func GetLogger added in v0.0.6

func GetLogger() Logger

GetLogger returns the currently active package-level Logger. It is the entry point submodules use to obtain the shared logger without taking a direct dependency on any logging framework.

func NewSlogLogger added in v0.0.6

func NewSlogLogger() Logger

NewSlogLogger builds a SlogLogger backed by the stdlib slog with sensible defaults: a text handler writing to stderr at INFO level.

Callers needing a different format / level / destination should either:

  • build their own *slog.Logger and wrap it: SlogLogger{L: myLogger}
  • or implement the Logger interface themselves and pass it to SetLogger.

type Manager added in v0.0.2

type Manager struct {
	// contains filtered or unexported fields
}

Manager manages the lifecycle and access of multiple Engine instances.

  • Useful when the application needs multiple engine instances, unified Init/Close, or name-based lookup.
  • If the project only needs a single global Engine, Manager is unnecessary.

func NewManager added in v0.0.2

func NewManager() *Manager

NewManager creates a Manager.

func (*Manager) CloseAll added in v0.0.2

func (m *Manager) CloseAll() error

CloseAll closes every registered Engine. Individual Close errors are ignored; the last non-nil error is returned.

func (*Manager) Get added in v0.0.2

func (m *Manager) Get(name string) (Engine, bool)

Get returns the registered Engine for the given name.

func (*Manager) GetDefault added in v0.0.2

func (m *Manager) GetDefault() (Engine, bool)

GetDefault returns the default Engine.

func (*Manager) InitAll added in v0.0.2

func (m *Manager) InitAll(ctx context.Context) error

InitAll calls Init on every registered Engine.

func (*Manager) Register added in v0.0.2

func (m *Manager) Register(name string, eng Engine) error

Register registers an Engine without initializing it. Returns an error if name already exists.

func (*Manager) Remove added in v0.0.2

func (m *Manager) Remove(name string, closeIfExists bool)

Remove unregisters the Engine with the given name. If closeIfExists is true and the Engine exists, it is also Closed.

func (*Manager) SetDefault added in v0.0.2

func (m *Manager) SetDefault(name string)

SetDefault sets the default engine name used by GetDefault.

type ModuleRegistrar added in v0.0.6

type ModuleRegistrar interface {
	// RegisterModule registers a module (e.g. map[string]any, native loader, ...)
	// under `name` so scripts can require/use it. The accepted shape of `module`
	// depends on the engine implementation.
	RegisterModule(name string, module any) error
}

ModuleRegistrar provides module registration for engines that support a module system (e.g. Lua's require, JavaScript's import).

Lightweight expression engines (CEL, Expr) typically do NOT implement this.

func AsModuleRegistrar added in v0.0.6

func AsModuleRegistrar(e any) ModuleRegistrar

AsModuleRegistrar returns the ModuleRegistrar capability of e, or nil if unsupported.

type ScriptEngine added in v0.0.6

type ScriptEngine interface {
	// GetType returns the Type identifier of this script engine.
	GetType() Type

	// Init initializes the script engine. Must be called before any Load*/Execute*.
	// Returns an error if initialization fails or if the engine is already initialized.
	Init(ctx context.Context) error

	// Close releases all resources held by the engine (runtime, VM, handles).
	// Returns an error if teardown fails. After Close, the engine must be re-Init'd
	// before reuse.
	Close() error

	// IsInitialized reports whether the engine has been initialized and not yet closed.
	IsInitialized() bool

	// GetLastError returns the last error recorded by the engine, or nil if none.
	GetLastError() error

	// ClearError clears the engine's last-error state.
	ClearError()
}

ScriptEngine is the minimal lifecycle interface that every engine implementation — regardless of its feature set — must satisfy.

Full-featured engines (Lua, JavaScript) additionally implement the optional capability interfaces below and are aggregated by Engine. Lightweight engines (CEL, Expr) may implement only ScriptEngine + ScriptExecutor and skip the rest.

type ScriptExecutor added in v0.0.6

type ScriptExecutor interface {
	// Execute runs every script previously loaded via Load/LoadMulti/LoadString and
	// returns the combined result.
	Execute(ctx context.Context) (any, error)

	// ExecuteFromKey loads the script identified by `key` from the bound Source and
	// immediately runs it, all in one step.
	ExecuteFromKey(ctx context.Context, key string) (any, error)

	// ExecuteFromKeys is the multi-key variant of ExecuteFromKey; results are
	// returned in the same order as `keys`.
	ExecuteFromKeys(ctx context.Context, keys []string) ([]any, error)

	// ExecuteString compiles and immediately runs an inline string script, bypassing
	// the bound Source. `name` is used for diagnostics.
	ExecuteString(ctx context.Context, name string, code string) (any, error)
}

ScriptExecutor provides script execution capabilities.

func AsExecutor added in v0.0.6

func AsExecutor(e any) ScriptExecutor

AsExecutor returns the ScriptExecutor capability of e, or nil if unsupported.

type ScriptLoader added in v0.0.6

type ScriptLoader interface {
	// SetSource binds a ScriptSource (FileSource / S3 / Mem / Multi / ...) to the
	// engine. Subsequent Load / ExecuteFromKey / ExecuteFromKeys calls read through it.
	// Passing nil clears any previously bound source.
	SetSource(source source.Reader)

	// GetSource returns the currently bound ScriptSource, or nil if none has been set.
	GetSource() source.Reader

	// Load loads a single script from the bound Source using the given key
	// (path / object key / script id, ...). Loaded scripts are kept by the engine
	// for later Execute runs.
	Load(ctx context.Context, key string) error

	// LoadMulti loads multiple scripts from the bound Source in order.
	// It aborts on the first error.
	LoadMulti(ctx context.Context, keys []string) error

	// LoadString compiles an inline script given directly as a string. It does NOT
	// go through the bound Source; use Load/LoadMulti for source-driven loading.
	// `name` is used for diagnostics (stack traces, error messages).
	LoadString(ctx context.Context, name string, code string) error
}

ScriptLoader provides source-driven script loading.

Loading is uniformly driven by the bound ScriptSource so the engine itself stays decoupled from concrete IO mechanisms (filesystem, S3, memory, ...).

func AsLoader added in v0.0.6

func AsLoader(e any) ScriptLoader

AsLoader returns the ScriptLoader capability of e, or nil if unsupported.

type ScriptWatcher added in v0.0.6

type ScriptWatcher interface {
	// StartWatch starts watching the script identified by `key` for changes via the
	// bound Source's Watch capability. When a change is detected, the script is
	// automatically reloaded. Returns an error if the source doesn't implement
	// Watcher or is not bound.
	StartWatch(ctx context.Context, key string) error

	// StopWatch stops watching the script identified by `key` and cleans up
	// the associated goroutine.
	StopWatch(key string) error
}

ScriptWatcher provides hot-reload (Watch) capabilities for scripts bound via a Source that implements source.Watcher.

Engines that do not support hot-reload (CEL, Expr, ...) do NOT implement this.

func AsWatcher added in v0.0.6

func AsWatcher(e any) ScriptWatcher

AsWatcher returns the ScriptWatcher capability of e, or nil if unsupported.

type SlogLogger added in v0.0.6

type SlogLogger struct {
	// L is the underlying slog logger. It MUST be non-nil; [NewSlogLogger]
	// always returns a ready-to-use instance.
	L *slog.Logger
}

SlogLogger adapts the stdlib *slog.Logger to the Logger interface.

This is the reference implementation returned by NewSlogLogger. Callers that already own a configured *slog.Logger can wrap it directly:

scriptEngine.SetLogger(scriptEngine.SlogLogger{L: mySlogLogger})

func (SlogLogger) Debug added in v0.0.6

func (s SlogLogger) Debug(ctx context.Context, msg string, args ...any)

Debug forwards to slog.Logger.DebugContext.

func (SlogLogger) Error added in v0.0.6

func (s SlogLogger) Error(ctx context.Context, msg string, args ...any)

Error forwards to slog.Logger.ErrorContext.

func (SlogLogger) Info added in v0.0.6

func (s SlogLogger) Info(ctx context.Context, msg string, args ...any)

Info forwards to slog.Logger.InfoContext.

func (SlogLogger) Warn added in v0.0.6

func (s SlogLogger) Warn(ctx context.Context, msg string, args ...any)

Warn forwards to slog.Logger.WarnContext.

func (SlogLogger) With added in v0.0.6

func (s SlogLogger) With(args ...any) Logger

With returns a new SlogLogger whose underlying *slog.Logger has the given key-value pairs attached. This is typically used to distinguish modules, e.g., logger.With("module", "goja"). The returned logger will include these attributes in every log record it produces.

type Type

type Type string

Type identifies a script engine implementation.

const (
	UnknownType Type = "unknown"

	// LuaType is the Lua 5.1 engine powered by gopher-lua.
	LuaType Type = "lua"

	// JavaScriptType is the ECMAScript 5.1+ engine powered by goja.
	JavaScriptType Type = "javascript"

	// GPythonType is the pure-Go Python 3.4 engine powered by gpython.
	GPythonType Type = "gpython"

	// YaegiType is the native Go script engine powered by Traefik Yaegi.
	YaegiType Type = "yaegi"

	// WazeroType is the WebAssembly engine powered by tetratelabs/wazero.
	WazeroType Type = "wazero"

	// CELType is the Google Common Expression Language powered by cel-go.
	CELType Type = "cel"

	// ExprType is the lightweight expression engine powered by antonmedv/expr.
	ExprType Type = "expr"

	// StarlarkType is the hermetic / safe script engine powered by google/starlark-go.
	StarlarkType Type = "starlark"

	// TclType is the 100 %-compatible Tcl engine powered by modernc.org/tcl.
	TclType Type = "tcl"
)

func ListFactories

func ListFactories() []Type

ListFactories returns a snapshot of all currently registered Types.

Directories

Path Synopsis
javascript module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL