func (lua *LuaExt) exec(reqLogger log.Logger, app *LuaApp, appID, reqId, script string, w http.ResponseWriter, r *http.Request) int { // FIXME(tsileo) a debug mode, with a defer/recover // also parse the Lu error and show the bugging line! start := time.Now() httpClient := &http.Client{} // Initialize internal Lua module written in Go logger := loggerModule.New(reqLogger.New("ctx", "Lua"), start, reqId) response := responseModule.New() request := requestModule.New(r, reqId, lua.authFunc) blobstore := blobstoreModule.New(lua.blobStore) kvstore := kvstoreModule.New(lua.kvStore) bewit := bewitModule.New(reqLogger.New("ctx", "Lua bewit module"), r) template := templateModule.New() // Initialize Lua state L := luamod.NewState() defer L.Close() setCustomGlobals(L) L.PreloadModule("request", request.Loader) L.PreloadModule("response", response.Loader) L.PreloadModule("logger", logger.Loader) L.PreloadModule("blobstore", blobstore.Loader) L.PreloadModule("kvstore", kvstore.Loader) L.PreloadModule("bewit", bewit.Loader) L.PreloadModule("template", template.Loader) // TODO(tsileo) docstore module // TODO(tsileo) cookies module // TODO(tsileo) lru module // TODO(tsileo) cache module => to cache response // TODO(tsileo) load module from github directly? // TODO(tsileo) ETag support // 3rd party module luajson.Preload(L) L.PreloadModule("http", gluahttp.NewHttpModule(httpClient).Loader) // Set some global variables L.SetGlobal("reqID", luamod.LString(reqId)) L.SetGlobal("appID", luamod.LString(appID)) // Execute the code if err := L.DoString(script); err != nil { // FIXME better error, with debug mode? panic(err) } // Apply the Response object to the actual response response.WriteTo(w) // TODO save the logRecords in the AppStats and find a way to serve them over Server-Sent Events // keep them in memory with the ability to dump them in bulk as blob for later query // logRecords := logger.Records() for _, logRecord := range logger.Records() { app.logs = append(app.logs, logRecord) } reqLogger.Info("Script executed", "response", response, "duration", time.Since(start)) return response.Status() }
//luaMain creates a new lua state for each file in ./lua //and hands them the globals they need to interact with lazlo func luaMain(b *lazlo.Broker) { broker = b var luaDir *os.File luaDirName := "lua" if luaDirInfo, err := os.Stat(luaDirName); err == nil && luaDirInfo.IsDir() { luaDir, _ = os.Open(luaDirName) } else { lazlo.Logger.Error("Couldn't open the Lua Plugin dir: ", err) } luaFiles, _ := luaDir.Readdir(0) for _, f := range luaFiles { if f.IsDir() { continue } file := fmt.Sprintf("%s/%s", luaDirName, f.Name()) //make a new script entry script := LuaScript{ Robot: &Robot{ ID: len(LuaScripts), }, State: lua.NewState(), } defer script.State.Close() // register hear and respond inside this lua state script.State.SetGlobal("robot", luar.New(script.State, script.Robot)) //script.State.SetGlobal("respond", luar.New(script.State, Respond)) //script.State.SetGlobal("hear", luar.New(script.State, Hear)) LuaScripts = append(LuaScripts, script) // the lua script will register callbacks to the Cases if err := script.State.DoFile(file); err != nil { panic(err) } } //block waiting on events from the broker for { index, value, _ := reflect.Select(Cases) handle(index, value.Interface()) } }