gitee.com/KyleChenSource/lib-robot@v1.0.2/robottest/common/mlua/lua.go (about) 1 package mlua 2 3 import ( 4 "bufio" 5 "fmt" 6 "os" 7 "sync" 8 9 "gitee.com/KyleChenSource/lib-robot/robottest/log" 10 lua "github.com/yuin/gopher-lua" 11 "github.com/yuin/gopher-lua/parse" 12 ) 13 14 const ( 15 LuaPathPre = "lua" 16 ) 17 18 var ( 19 luaFiles sync.Map 20 luajson *lua.FunctionProto 21 ) 22 23 type LuaScript struct { 24 OnStart *lua.LFunction // OnStart(Action) 25 OnStop *lua.LFunction // OnStop(Action) 26 OnMsg *lua.LFunction // OnMsg(Action, msgId, msgJson) 27 } 28 29 type LuaCtx struct { 30 L *lua.LState 31 Tables map[string]*LuaScript 32 } 33 34 func LuaCtxCreate() *LuaCtx { 35 ret := &LuaCtx{ 36 L: lua.NewState(), 37 Tables: make(map[string]*LuaScript), 38 } 39 40 if luajson == nil { 41 c, err := CompileLua(fmt.Sprintf("%s/json.lua", LuaPathPre)) 42 if err != nil { 43 log.LogError("CompileLua json.lua err:%s", err.Error()) 44 return nil 45 } 46 luajson = c 47 } 48 49 topB := ret.L.GetTop() 50 err := DoCompiledFile(ret.L, luajson) 51 if err != nil { 52 log.LogError("DoCompiledFile json.lua err:%s", err.Error()) 53 return nil 54 } 55 topE := ret.L.GetTop() 56 if topE-topB != 1 { 57 log.LogError("DoCompiledFile json.lua return:%d", topE-topB) 58 return nil 59 } 60 table := ret.L.CheckTable(topE) 61 if table == nil { 62 log.LogError("DoCompiledFile json.lua return not table") 63 return nil 64 } 65 66 preload := ret.L.GetField(ret.L.GetField(ret.L.Get(lua.EnvironIndex), "package"), "loaded") 67 if _, ok := preload.(*lua.LTable); !ok { 68 log.LogError("no package[loaded]") 69 return nil 70 } 71 ret.L.SetField(preload, "json", table) 72 73 return ret 74 } 75 76 func (this *LuaCtx) Script(file string) (*LuaScript, error) { 77 t, ok := this.Tables[file] 78 if ok { 79 return t, nil 80 } 81 82 f, ok := luaFiles.Load(file) 83 if !ok { 84 c, err := CompileLua(fmt.Sprintf("%s/%s", LuaPathPre, file)) 85 if err != nil { 86 return nil, err 87 } 88 89 f, _ = luaFiles.LoadOrStore(file, c) 90 } 91 92 p := f.(*lua.FunctionProto) 93 topB := this.L.GetTop() 94 err := DoCompiledFile(this.L, p) 95 if err != nil { 96 return nil, err 97 } 98 topE := this.L.GetTop() 99 if topE-topB != 1 { 100 return nil, fmt.Errorf("return param:%d", topE-topB) 101 } 102 103 table := this.L.CheckTable(topE) 104 if table == nil { 105 return nil, fmt.Errorf("return param:%s", this.L.Get(topE).Type().String()) 106 } 107 108 this.L.SetGlobal(file, table) 109 script := LuaScript{} 110 111 function := table.RawGetString("onStart") 112 if function == nil { 113 return nil, fmt.Errorf("onStart nil") 114 } 115 if function.Type() != lua.LTFunction { 116 return nil, fmt.Errorf("onStart type:%s", function.Type().String()) 117 } 118 script.OnStart = function.(*lua.LFunction) 119 120 function = table.RawGetString("onMsg") 121 if function == nil { 122 return nil, fmt.Errorf("onMsg nil") 123 } 124 if function.Type() != lua.LTFunction { 125 return nil, fmt.Errorf("onMsg type:%s", function.Type().String()) 126 } 127 script.OnMsg = function.(*lua.LFunction) 128 129 function = table.RawGetString("onStop") 130 if function == nil { 131 return nil, fmt.Errorf("onStop nil") 132 } 133 if function.Type() != lua.LTFunction { 134 return nil, fmt.Errorf("onStop type:%s", function.Type().String()) 135 } 136 script.OnStop = function.(*lua.LFunction) 137 this.Tables[file] = &script 138 139 return &script, nil 140 } 141 142 // CompileLua reads the passed lua file from disk and compiles it. 143 func CompileLua(filePath string) (*lua.FunctionProto, error) { 144 file, err := os.Open(filePath) 145 defer file.Close() 146 if err != nil { 147 return nil, err 148 } 149 reader := bufio.NewReader(file) 150 chunk, err := parse.Parse(reader, filePath) 151 if err != nil { 152 return nil, err 153 } 154 proto, err := lua.Compile(chunk, filePath) 155 if err != nil { 156 return nil, err 157 } 158 return proto, nil 159 } 160 161 // DoCompiledFile takes a FunctionProto, as returned by CompileLua, and runs it in the LState. It is equivalent 162 // to calling DoFile on the LState with the original source file. 163 func DoCompiledFile(L *lua.LState, proto *lua.FunctionProto) error { 164 lfunc := L.NewFunctionFromProto(proto) 165 L.Push(lfunc) 166 return L.PCall(0, lua.MultRet, nil) 167 }