add plugins
All checks were successful
Build Multi-Platform Binaries / build (push) Successful in 11m9s
All checks were successful
Build Multi-Platform Binaries / build (push) Successful in 11m9s
This commit is contained in:
148
pkg/plugin/wasm/module.go
Normal file
148
pkg/plugin/wasm/module.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package wasm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gotunnel/pkg/plugin"
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
// WASMPlugin 封装 WASM 模块作为 ProxyHandler
|
||||
type WASMPlugin struct {
|
||||
name string
|
||||
metadata plugin.PluginMetadata
|
||||
runtime *Runtime
|
||||
compiled wazero.CompiledModule
|
||||
config map[string]string
|
||||
}
|
||||
|
||||
// NewWASMPlugin 从 WASM 字节创建 plugin
|
||||
func NewWASMPlugin(ctx context.Context, rt *Runtime, name string, wasmBytes []byte) (*WASMPlugin, error) {
|
||||
compiled, err := rt.runtime.CompileModule(ctx, wasmBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("compile module: %w", err)
|
||||
}
|
||||
|
||||
p := &WASMPlugin{
|
||||
name: name,
|
||||
runtime: rt,
|
||||
compiled: compiled,
|
||||
}
|
||||
|
||||
// 尝试获取元数据
|
||||
if err := p.loadMetadata(ctx); err != nil {
|
||||
// 使用默认元数据
|
||||
p.metadata = plugin.PluginMetadata{
|
||||
Name: name,
|
||||
Type: plugin.PluginTypeProxy,
|
||||
Source: plugin.PluginSourceWASM,
|
||||
}
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// loadMetadata 从 WASM 模块加载元数据
|
||||
func (p *WASMPlugin) loadMetadata(ctx context.Context) error {
|
||||
// 创建临时实例获取元数据
|
||||
inst, err := p.runtime.runtime.InstantiateModule(ctx, p.compiled, wazero.NewModuleConfig())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer inst.Close(ctx)
|
||||
|
||||
metadataFn := inst.ExportedFunction("metadata")
|
||||
if metadataFn == nil {
|
||||
return fmt.Errorf("metadata function not exported")
|
||||
}
|
||||
|
||||
allocFn := inst.ExportedFunction("alloc")
|
||||
if allocFn == nil {
|
||||
return fmt.Errorf("alloc function not exported")
|
||||
}
|
||||
|
||||
// 分配缓冲区
|
||||
results, err := allocFn.Call(ctx, 1024)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bufPtr := uint32(results[0])
|
||||
|
||||
// 调用 metadata 函数
|
||||
results, err = metadataFn.Call(ctx, uint64(bufPtr), 1024)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
actualLen := uint32(results[0])
|
||||
|
||||
// 读取元数据
|
||||
mem := inst.Memory()
|
||||
data, ok := mem.Read(bufPtr, actualLen)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to read metadata")
|
||||
}
|
||||
|
||||
return json.Unmarshal(data, &p.metadata)
|
||||
}
|
||||
|
||||
// Metadata 返回 plugin 信息
|
||||
func (p *WASMPlugin) Metadata() plugin.PluginMetadata {
|
||||
return p.metadata
|
||||
}
|
||||
|
||||
// Init 初始化 plugin
|
||||
func (p *WASMPlugin) Init(config map[string]string) error {
|
||||
p.config = config
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandleConn 处理连接
|
||||
func (p *WASMPlugin) HandleConn(conn interface{}, dialer plugin.Dialer) error {
|
||||
// WASM plugin 的连接处理需要更复杂的实现
|
||||
// 这里提供基础框架,实际实现需要注册 host functions
|
||||
return fmt.Errorf("WASM plugin HandleConn not fully implemented")
|
||||
}
|
||||
|
||||
// Close 关闭 plugin
|
||||
func (p *WASMPlugin) Close() error {
|
||||
return p.compiled.Close(context.Background())
|
||||
}
|
||||
|
||||
// RegisterHostFunctions 注册 host functions 到 wazero 运行时
|
||||
func RegisterHostFunctions(ctx context.Context, r wazero.Runtime) (wazero.CompiledModule, error) {
|
||||
return r.NewHostModuleBuilder("env").
|
||||
NewFunctionBuilder().
|
||||
WithFunc(hostLog).
|
||||
Export("log").
|
||||
NewFunctionBuilder().
|
||||
WithFunc(hostNow).
|
||||
Export("now").
|
||||
Compile(ctx)
|
||||
}
|
||||
|
||||
// host function 实现
|
||||
func hostLog(ctx context.Context, m api.Module, level uint32, msgPtr, msgLen uint32) {
|
||||
data, ok := m.Memory().Read(msgPtr, msgLen)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
prefix := "[WASM]"
|
||||
switch plugin.LogLevel(level) {
|
||||
case plugin.LogDebug:
|
||||
prefix = "[WASM DEBUG]"
|
||||
case plugin.LogInfo:
|
||||
prefix = "[WASM INFO]"
|
||||
case plugin.LogWarn:
|
||||
prefix = "[WASM WARN]"
|
||||
case plugin.LogError:
|
||||
prefix = "[WASM ERROR]"
|
||||
}
|
||||
fmt.Printf("%s %s\n", prefix, string(data))
|
||||
}
|
||||
|
||||
func hostNow(ctx context.Context) int64 {
|
||||
return ctx.Value("now").(func() int64)()
|
||||
}
|
||||
Reference in New Issue
Block a user