package interceptor import ( "fmt" "os" "path/filepath" "github.com/mattn/anko/env" "github.com/mattn/anko/vm" ) type Ankointerceptor struct { importMap map[string]interface{} libMap map[string]interface{} liberalises []uintptr ankoEnv *env.Env } func NewAnkointerceptor(ankoEnv *env.Env) *Ankointerceptor { if ankoEnv == nil { ankoEnv = env.NewEnv() } a := &Ankointerceptor{ importMap: make(map[string]interface{}), libMap: make(map[string]interface{}), liberalises: make([]uintptr, 0), ankoEnv: ankoEnv, } _ = a.ankoEnv.Define("println", fmt.Println) _ = a.ankoEnv.Define("loadLibrary", func(libPath string, libFuncMap map[string]funcType) interface{} { return a.loadLibrary(libPath, libFuncMap) }) a.importMap["fs"] = &FileModule{} a.importMap["net"] = &NetModule{} a.importMap["process"] = &ProcessModule{} a.importMap["shell"] = &ShellModule{} return a } // Exec executes the specified script within the Anko environment. // It sets up the environment with necessary variables and methods, // reads the script file, and executes it, returning the result or an error. // // Parameters: // - script: Path to the script file to be executed. // // Returns: // - interface{}: The result of the script execution. // - error: An error if the script file cannot be read or execution fails. 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() // Configure the Anko environment with required variables and methods if scriptPath == "" { cdir, _ := os.Getwd() scriptPath = filepath.Join(cdir, "tmp") } _ = e.Define("Require", a.genRequireMethod(scriptPath)) _ = e.Define("__filename", scriptPath) _ = e.Define("__dirname", filepath.Dir(scriptPath)) // Execute the script code in the prepared environment result, err := vm.Execute(e, nil, scriptContent) if err != nil { fmt.Println(err) return nil, err } return result, nil } // genRequireMethod 创建模块解析闭包函数 // 该函数用于处理模块路径解析和缓存机制: // 1. 优先从importMap缓存中查找已加载模块 // 2. 对相对路径自动转换为基于basePath的绝对路径 // 3. 执行模块加载后自动缓存结果 // 参数: // // basePath - 模块基础路径,用于解析相对路径 // // 返回: // // 闭包函数,接收模块路径s,返回解析后的模块对象 func (a *Ankointerceptor) genRequireMethod(basePath string) interface{} { return func(s string) interface{} { if r, ok := a.importMap[s]; ok { return r } // 将相对路径转换为基于basePath的绝对路径 if !filepath.IsAbs(s) { s = filepath.Join(filepath.Dir(basePath), s) } if _, ok := a.importMap[s]; ok { return a.importMap[s] } // 执行模块加载并将结果缓存 result, err := a.Exec(s) if err != nil { panic(err) } a.importMap[s] = 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 }