func register(L *lua.State, table string, values Map, convertFun bool) { pop := true if table == "*" { pop = false } else if len(table) > 0 { L.GetGlobal(table) if L.IsNil(-1) { L.NewTable() L.SetGlobal(table) L.GetGlobal(table) } } else { L.GetGlobal("_G") } for name, val := range values { t := reflect.TypeOf(val) if t.Kind() == reflect.Func { if convertFun { L.PushGoFunction(GoLuaFunc(L, val)) } else { lf := val.(func(*lua.State) int) L.PushGoFunction(lf) } } else { GoToLua(L, t, valueOf(val), false) } L.SetField(-2, name) } if pop { L.Pop(1) } }
func (p *LuaPlugin) prepContext(L *lua.State, req *http.Request, ctx *apiplexy.APIContext) { var clientIP string if req.Header.Get("X-Forwarded-For") != "" { clientIP = req.Header.Get("X-Forwarded-For") } else { clientIP, _, _ = net.SplitHostPort(req.RemoteAddr) } headers := make(map[string]interface{}, len(req.Header)) for k, vs := range req.Header { headers[k] = strings.Join(vs, " ") } request := map[string]interface{}{ "path": req.URL.Path, "method": req.Method, "ip": clientIP, "referrer": req.Referer(), "browser": req.UserAgent(), "headers": headers, } pushMap(L, request, false) L.SetGlobal("request") pushMap(L, structs.Map(ctx), true) L.SetGlobal("context") }
func outputNumbersToStrings(L *lua.State) { L.GetGlobal("output") if !L.IsTable(-1) { L.NewTable() L.SetGlobal("output") } L.GetField(-1, "tags") if L.IsTable(-1) { // First key. L.PushNil() for L.Next(-2) != 0 { // Use 'key' at index -2 and 'value' at index -1. if L.IsString(-2) && L.IsString(-1) { // Convert numbers to strings. L.ToString(-1) L.SetField(-3, L.ToString(-2)) } else { // Remove 'value' and keep 'key' for next iteration. L.Pop(1) } } } L.Pop(1) L.Pop(1) }
// goToLua copies Go values to Lua and sets the result to global 'name'. // Compound types are deep-copied. // Functions are automatically converted to 'func (L *lua.State) int'. func goToLua(L *lua.State, name string, val interface{}) { t := reflect.TypeOf(val) if t.Kind() == reflect.Func { L.PushGoFunction(luar.GoLuaFunc(L, val)) } else { luar.GoToLua(L, t, reflect.ValueOf(val), true) } L.SetGlobal(name) }
// Register makes a number of Go values available in Lua code. // 'values' is a map of strings to Go values. // // - If table is non-nil, then create or reuse a global table of that name and // put the values in it. // // - If table is '' then put the values in the global table (_G). // // - If table is '*' then assume that the table is already on the stack. func Register(L *lua.State, table string, values Map) { pop := true if table == "*" { pop = false } else if len(table) > 0 { L.GetGlobal(table) if L.IsNil(-1) { L.NewTable() L.SetGlobal(table) L.GetGlobal(table) } } else { L.GetGlobal("_G") } for name, val := range values { GoToLua(L, nil, reflect.ValueOf(val), false) L.SetField(-2, name) } if pop { L.Pop(1) } }
func installWorld(state *lua.State) { log.Println("Installing world") printStackTypes(state) state.NewMetaTable(ThingMetaTableName) // ( -- mtbl ) state.SetMetaMethod("__index", MessThingIndex) // ( mtbl -- mtbl ) state.Pop(1) // ( mtbl -- ) worldTable := map[string]interface{}{ /* "Root": "Create": func... */ } pushValue(state, worldTable) // Install Thing types as singleton sentinel values. As userdata, these will only compare if the values are exactly equal. state.NewUserdata(uintptr(0)) state.SetField(-2, "Player") state.NewUserdata(uintptr(0)) state.SetField(-2, "Place") state.NewUserdata(uintptr(0)) state.SetField(-2, "Program") state.NewUserdata(uintptr(0)) state.SetField(-2, "Action") state.NewUserdata(uintptr(0)) state.SetField(-2, "Thing") state.SetGlobal("world") state.GetGlobal("table") // ( -- tblTable ) state.PushGoFunction(TableFormat) state.SetField(-2, "format") state.Pop(1) // ( tblTable -- ) log.Println("Finished installing world") printStackTypes(state) }
func register(L *lua.State, table string, values Map, convertFun bool) { pop := true if table == "*" { pop = false } else if len(table) > 0 { L.GetGlobal(table) if L.IsNil(-1) { L.NewTable() L.SetGlobal(table) L.GetGlobal(table) } } else { L.GetGlobal("_G") } for name, val := range values { t := reflect.TypeOf(val) if t.Kind() == reflect.Func { if convertFun { L.PushGoFunction(GoLuaFunc(L, val)) } else { lf := val.(func(*lua.State) int) L.PushGoFunction(lf) } } else { GoToLua(L, t, valueOf(val), false) } L.SetField(-2, name) if t.Kind() == reflect.Func { var lf func(*lua.State) int if convertFun { lf = GoLuaFunc(L, val) } else { lf = val.(func(*lua.State) int) } L.PushGoFunction(func(L *lua.State) (ret int) { defer func() { if err2 := recover(); err2 != nil { GoToLua(L, typeof(err2), valueOf(err2), false) ret = 1 return } }() ret = lf(L) pos := L.GetTop() - ret + 1 L.PushNil() L.Insert(pos) for i := 0; i < L.GetTop(); i++ { fmt.Println(L.Typename(int(L.Type(i + 1)))) } return ret + 1 }) L.SetField(-2, "safe_"+name) } } if pop { L.Pop(1) } }
func NilGlobal(L *lua.State, name string) { L.PushNil() L.SetGlobal(name) }
func (p *LuaPlugin) enableDebug(L *lua.State) { L.DoString(inspectLua) L.SetGlobal("inspect") }
// 'exist' is optional. func run(L *lua.State, registryIndex string, code string, input *inputInfo, output *outputInfo, exist *inputInfo) error { // Restore the sandbox. err := L.DoString(luaRestoreSandbox) if err != nil { log.Fatal("Cannot load function to restore sandbox", err) } L.PushString(registryWhitelist) L.GetTable(lua.LUA_REGISTRYINDEX) err = L.Call(1, 0) if err != nil { log.Fatal("Failed to restore sandbox", err) } goToLua(L, "input", *input) goToLua(L, "output", *output) if exist != nil { goToLua(L, "existinfo", *exist) } // Shortcut (mostly for prescript and postscript). L.GetGlobal("input") L.GetField(-1, "tags") L.SetGlobal("i") L.Pop(1) L.GetGlobal("output") L.GetField(-1, "tags") L.SetGlobal("o") L.Pop(1) // Call the compiled script. L.PushString(registryIndex) L.GetTable(lua.LUA_REGISTRYINDEX) L.PushString(code) if L.IsTable(-2) { L.GetTable(-2) if L.IsFunction(-1) { err := L.Call(0, 0) if err != nil { L.SetTop(0) return fmt.Errorf("%s", err) } } else { L.Pop(1) } } else { L.Pop(1) } L.Pop(1) // Allow tags to be numbers for convenience. outputNumbersToStrings(L) L.GetGlobal("output") r := luar.LuaToGo(L, reflect.TypeOf(*output), -1) L.Pop(1) *output = r.(outputInfo) return nil }