实现模块注册功能及脚本执行优化

This commit is contained in:
kingecg 2025-09-20 16:35:33 +08:00
parent ae43530608
commit b3c6f070da
4 changed files with 117 additions and 12 deletions

2
go.mod
View File

@ -1,6 +1,6 @@
module git.kingecg.top/kingecg/gosh module git.kingecg.top/kingecg/gosh
go 1.23.1 go 1.23
require ( require (
github.com/ebitengine/purego v0.8.4 github.com/ebitengine/purego v0.8.4

View File

@ -17,7 +17,9 @@ type Ankointerceptor struct {
} }
func NewAnkointerceptor(ankoEnv *env.Env) *Ankointerceptor { func NewAnkointerceptor(ankoEnv *env.Env) *Ankointerceptor {
if ankoEnv == nil {
ankoEnv = env.NewEnv()
}
a := &Ankointerceptor{ a := &Ankointerceptor{
importMap: make(map[string]interface{}), importMap: make(map[string]interface{}),
libMap: make(map[string]interface{}), libMap: make(map[string]interface{}),
@ -46,18 +48,60 @@ func NewAnkointerceptor(ankoEnv *env.Env) *Ankointerceptor {
// - interface{}: The result of the script execution. // - interface{}: The result of the script execution.
// - error: An error if the script file cannot be read or execution fails. // - error: An error if the script file cannot be read or execution fails.
func (a *Ankointerceptor) Exec(script string) (interface{}, error) { func (a *Ankointerceptor) Exec(script string) (interface{}, error) {
st, err := os.Stat(script)
if err != nil {
return nil, err
}
if st.IsDir() {
toExec := filepath.Join(script, "index.ank")
return a.exec(toExec, script)
}
if !filepath.IsAbs(script) {
script = filepath.Join(os.Getenv("PWD"), script)
}
content, err := os.ReadFile(script)
if err != nil {
return nil, err
}
scriptContent := string(content)
result, err := a.exec(scriptContent, script)
if err != nil {
return nil, err
}
return result, nil
}
// ExecContent executes the specified script content within the Anko environment.
// It sets up the environment with necessary variables and methods,
// executes the script content, and returns the result or an error.
//
// Parameters:
// - scriptContent: The script content to be executed.
//
// Returns:
// - interface{}: The result of the script execution.
// - error: An error if the script execution fails.
func (a *Ankointerceptor) ExecContent(scriptContent string) (interface{}, error) {
result, err := a.exec(scriptContent, "")
if err != nil {
return nil, err
}
return result, nil
}
func (a *Ankointerceptor) exec(scriptContent string, scriptPath string) (interface{}, error) {
e := a.ankoEnv.Copy() e := a.ankoEnv.Copy()
// Configure the Anko environment with required variables and methods // Configure the Anko environment with required variables and methods
e.Define("Require", a.genRequireMethod(script)) if scriptPath == "" {
e.Define("__filename", script) cdir, _ := os.Getwd()
e.Define("__dirname", filepath.Dir(script)) scriptPath = filepath.Join(cdir, "tmp")
scriptbytes, frr := os.ReadFile(script)
if frr != nil {
return nil, frr
} }
scriptcode := string(scriptbytes) e.Define("Require", a.genRequireMethod(scriptPath))
e.Define("__filename", scriptPath)
e.Define("__dirname", filepath.Dir(scriptPath))
// Execute the script code in the prepared environment // Execute the script code in the prepared environment
result, err := vm.Execute(e, nil, scriptcode) result, err := vm.Execute(e, nil, scriptContent)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return nil, err return nil, err
@ -71,8 +115,11 @@ func (a *Ankointerceptor) Exec(script string) (interface{}, error) {
// 2. 对相对路径自动转换为基于basePath的绝对路径 // 2. 对相对路径自动转换为基于basePath的绝对路径
// 3. 执行模块加载后自动缓存结果 // 3. 执行模块加载后自动缓存结果
// 参数: // 参数:
//
// basePath - 模块基础路径,用于解析相对路径 // basePath - 模块基础路径,用于解析相对路径
//
// 返回: // 返回:
//
// 闭包函数接收模块路径s返回解析后的模块对象 // 闭包函数接收模块路径s返回解析后的模块对象
func (a *Ankointerceptor) genRequireMethod(basePath string) interface{} { func (a *Ankointerceptor) genRequireMethod(basePath string) interface{} {
return func(s string) interface{} { return func(s string) interface{} {
@ -95,3 +142,19 @@ func (a *Ankointerceptor) genRequireMethod(basePath string) interface{} {
return result return result
} }
} }
func (a *Ankointerceptor) RegistModule(name string, m map[string]interface{}) {
_, ok := a.importMap[name]
if ok {
panic("Module already exists")
}
a.importMap[name] = m
}
func (a *Ankointerceptor) RegistStructAsModule(name string, s interface{}) {
_, ok := a.importMap[name]
if ok {
panic("Module already exists")
}
a.importMap[name] = s
}

View File

@ -1,6 +1,7 @@
package interceptor package interceptor
import ( import (
"fmt"
"path/filepath" "path/filepath"
"runtime" "runtime"
"testing" "testing"
@ -33,3 +34,41 @@ func TestAnkointerceptor_loadlib(t *testing.T) {
t.Errorf("Loadso test failed") t.Errorf("Loadso test failed")
} }
} }
func TestAnkointerceptor_RegistModule(t *testing.T) {
e := env.NewEnv()
interceptor := NewAnkointerceptor(e)
_, file, _, _ := runtime.Caller(0)
scriptPath := filepath.Join(filepath.Dir(file), "testdata/test_injectmodule.ank")
m := make(map[string]interface{})
m["Hi"] = func() string {
return "Hello, world!"
}
interceptor.RegistModule("inject", m)
v, _ := interceptor.Exec(scriptPath)
if v != "Hello, world!" {
t.Errorf("Inject module test failed")
}
}
type TestStruct struct {
Name string
}
func (t *TestStruct) Hi() string {
return fmt.Sprintf("Hello, %s!", t.Name)
}
func TestAnkointerceptor_RegistStructAsModule(t *testing.T) {
e := env.NewEnv()
interceptor := NewAnkointerceptor(e)
_, file, _, _ := runtime.Caller(0)
scriptPath := filepath.Join(filepath.Dir(file), "testdata/test_injectmodule.ank")
interceptor.RegistStructAsModule("inject", &TestStruct{"world"})
v, _ := interceptor.Exec(scriptPath)
if v != "Hello, world!" {
t.Errorf("Inject module test failed")
}
}

View File

@ -0,0 +1,3 @@
inject=Require("inject")
x=inject.Hi()
x