From ccfc876aae6598cdbefe51369aa5b25bba538ca6 Mon Sep 17 00:00:00 2001 From: taotao Date: Fri, 17 May 2024 19:28:21 +0800 Subject: [PATCH] feat : display the print logs of the driver side #26 --- driver/bot/behavior/node.go | 5 ++ driver/bot/behavior/tick.go | 22 +++---- driver/bot/bot.go | 45 +++++++++++++-- driver/bot/pool/lua_state.go | 12 ++++ driver/openapi/api_def.go | 9 +++ driver/openapi/api_server.go | 39 +++++++++++++ driver/script/module/log.go | 58 +++++++++++++++++++ editor/src/constant/api.tsx | 5 +- editor/src/pages/edit/blackboard.tsx | 85 +++++++++++++++------------- editor/src/utils/request.js | 2 +- 10 files changed, 227 insertions(+), 55 deletions(-) create mode 100644 driver/script/module/log.go diff --git a/driver/bot/behavior/node.go b/driver/bot/behavior/node.go index 7c757c2..b71e198 100644 --- a/driver/bot/behavior/node.go +++ b/driver/bot/behavior/node.go @@ -61,6 +61,11 @@ func (a *Node) ID() string { return a.id } +// Name 返回节点的名称 +func (a *Node) Name() string { + return "" +} + func (a *Node) Type() string { return a.ty } diff --git a/driver/bot/behavior/tick.go b/driver/bot/behavior/tick.go index 446c58d..f8877c1 100644 --- a/driver/bot/behavior/tick.go +++ b/driver/bot/behavior/tick.go @@ -82,7 +82,7 @@ ext: return state, changestr, err } -func (t *Tick) Do(mod Mode) (state string, end bool) { +func (t *Tick) Do(mod Mode) (state string, end bool, logs []string) { nods := t.blackboard.GetOpenNods() t.blackboard.ThreadInfoReset() @@ -94,7 +94,7 @@ func (t *Tick) Do(mod Mode) (state string, end bool) { err = n.onTick(t) state, msg, parseerr = t.stateCheck(mod, n.getType()) - + // thread 信息用于编辑器标记运行时节点信息(展示项 threadInfo := ThreadInfo{ Number: n.getBase().getThread(), CurNod: n.getBase().ID(), @@ -102,12 +102,15 @@ func (t *Tick) Do(mod Mode) (state string, end bool) { } if err != nil { - threadInfo.ErrMsg = fmt.Sprintf("tick err %v", err.Error()) - fmt.Println("tick err", threadInfo.ErrMsg) + logs = append(logs, fmt.Sprintf("check err thread:%v name:%v id:%v\n%v", + n.getBase().getThread(), + n.getBase().ID(), + n.getBase().Name(), + err.Error()), + ) } if parseerr != nil { - threadInfo.ErrMsg = fmt.Sprintf("%v parse err %v", threadInfo.ErrMsg, parseerr.Error()) - fmt.Println("tick parse err", threadInfo.ErrMsg) + //threadInfo.ErrMsg = fmt.Sprintf("%v parse err %v", threadInfo.ErrMsg, parseerr.Error()) } if state != Succ { @@ -115,12 +118,9 @@ func (t *Tick) Do(mod Mode) (state string, end bool) { end = true } else if state == Break { end = true - threadInfo.ErrMsg = fmt.Sprintf("script break err %v", msg) - fmt.Println("tick break err", threadInfo.ErrMsg) } else if state == Error { // 节点脚本出错,脚本逻辑自行抛出的错误 - threadInfo.ErrMsg = fmt.Sprintf("script err %v", msg) - fmt.Println("tick script err", threadInfo.ErrMsg) + //threadInfo.ErrMsg = fmt.Sprintf("script err %v", msg) } } @@ -143,5 +143,5 @@ func (t *Tick) Do(mod Mode) (state string, end bool) { } ext: - return state, end + return state, end, logs } diff --git a/driver/bot/bot.go b/driver/bot/bot.go index cc3907b..311d309 100644 --- a/driver/bot/bot.go +++ b/driver/bot/bot.go @@ -166,13 +166,21 @@ func NewWithBehaviorTree(path string, bt *behavior.Tree, mode behavior.Mode, nam fmt.Println("set bot name", err.Error()) } + bot.addLog(fmt.Sprintf("create bot id %v name %v success", bot.id, bot.name)) + return bot } func (b *Bot) loopThread(doneCh chan<- string, errch chan<- ErrInfo) { for { - state, end := b.tick.Do(b.mod) + state, end, logs := b.tick.Do(b.mod) + if len(logs) != 0 { + for _, log := range logs { + b.addLog(log) + } + } + if end { doneCh <- b.id goto ext @@ -208,7 +216,13 @@ func (b *Bot) RunByBlock() error { }() for { - state, end := b.tick.Do(b.mod) + state, end, logs := b.tick.Do(b.mod) + if len(logs) != 0 { + for _, log := range logs { + b.addLog(log) + } + } + if end { return nil } @@ -262,8 +276,24 @@ func (b *Bot) close() { pool.FreeState(b.bs) } - fmt.Println("bot", b.Name(), "batch", b.batch, "idx", b.id, "close") + b.addLog(fmt.Sprintf("close bot id %v name %v success", b.id, b.name)) +} + +// PopLog - 弹出一条日志 +func (b *Bot) PopLog() string { + line := b.bs.LogMod.Pop() + return line +} + +func (b *Bot) addLog(log string) { + fmt.Println("=>", log) + + log = time.Now().Format("2006-01-02 15:04:05") + " =================>\n" + log + + if b.mod != behavior.Thread { + b.bs.LogMod.Push(log) + } } type State int32 @@ -281,7 +311,14 @@ func (b *Bot) RunByStep() State { stepmu.Lock() defer stepmu.Unlock() - state, end := b.tick.Do(b.mod) + // 这边的错误日志需要记录下 + state, end, logs := b.tick.Do(b.mod) + if len(logs) != 0 { + for _, log := range logs { + b.addLog(log) + } + } + if end { return SEnd } diff --git a/driver/bot/pool/lua_state.go b/driver/bot/pool/lua_state.go index 7a80d34..dfb14a8 100644 --- a/driver/bot/pool/lua_state.go +++ b/driver/bot/pool/lua_state.go @@ -22,6 +22,7 @@ type BotState struct { base64Mod *script.Base64Module mgoMod *script.MgoModule md5Mod *script.MD5Module + LogMod *script.LogModule } func (pl *lStatePool) Get() *BotState { @@ -50,6 +51,7 @@ func _new_state() *BotState { base64Mod: &script.Base64Module{}, mgoMod: &script.MgoModule{}, md5Mod: &script.MD5Module{}, + LogMod: &script.LogModule{}, } b.L.PreloadModule("proto", b.protoMod.Loader) @@ -60,6 +62,7 @@ func _new_state() *BotState { b.L.PreloadModule("base64", b.base64Mod.Loader) b.L.PreloadModule("mgo", b.mgoMod.Loader) b.L.PreloadModule("md5", b.md5Mod.Loader) + b.L.PreloadModule("log", b.LogMod.Loader) return b } @@ -80,7 +83,14 @@ func GetState() *BotState { return luaPool.Get() } +func (bs *BotState) Clean() { + // module clean + bs.LogMod.Clean() +} + func PutState(state *BotState) { + state.Clean() + luaPool.Put(state) } @@ -89,6 +99,8 @@ func NewState() *BotState { } func FreeState(state *BotState) { + state.Clean() + state.L.Close() } diff --git a/driver/openapi/api_def.go b/driver/openapi/api_def.go index d02e25e..e799f4a 100644 --- a/driver/openapi/api_def.go +++ b/driver/openapi/api_def.go @@ -130,3 +130,12 @@ type PrefabSetTagsReq struct { Name string `json:"name"` Tags []string `json:"tags"` } + +// ------------------------ runtime ------------------------ +type RuntimeInfoReq struct { + ID string +} + +type RuntimeInfoRes struct { + Msg string +} diff --git a/driver/openapi/api_server.go b/driver/openapi/api_server.go index 4bcba14..8a55b29 100644 --- a/driver/openapi/api_server.go +++ b/driver/openapi/api_server.go @@ -756,6 +756,43 @@ EXT: return nil } +func BotRuntimeInfo(ctx echo.Context) error { + code := Succ + var b *bot.Bot + req := &RuntimeInfoReq{} + res := &response{} + body := &RuntimeInfoRes{} + + bts, err := ioutil.ReadAll(ctx.Request().Body) + if err != nil { + code = ErrContentRead // tmp + fmt.Println(err.Error()) + goto EXT + } + err = json.Unmarshal(bts, &req) + if err != nil { + code = ErrContentRead // tmp + fmt.Println(err.Error()) + goto EXT + } + + b = factory.Global.FindBot(req.ID) + if b == nil { + code = ErrCantFindBot + goto EXT + } + + body.Msg = b.PopLog() + +EXT: + res.Code = int(code) + res.Msg = errmap[code] + res.Body = body + + ctx.JSON(http.StatusOK, res) + return nil +} + func ReqPrint() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { @@ -774,6 +811,8 @@ func Route(e *echo.Echo) { return nil }) + e.POST("/runtime.info", BotRuntimeInfo) + e.POST("/file.uploadTxt", FileTextUpload) e.POST("/file.uploadBlob", FileBlobUpload) e.POST("/file.remove", FileRemove) diff --git a/driver/script/module/log.go b/driver/script/module/log.go new file mode 100644 index 0000000..6823155 --- /dev/null +++ b/driver/script/module/log.go @@ -0,0 +1,58 @@ +package script + +import ( + "sync" + + lua "github.com/yuin/gopher-lua" +) + +type LogModule struct { + logs []string + sync.Mutex +} + +func (lm *LogModule) Loader(L *lua.LState) int { + mod := L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{ + "info": lm.info, + }) + L.Push(mod) + return 1 +} + +// info - 脚本端添加一行日志 +func (lm *LogModule) info(L *lua.LState) int { + lm.Lock() + defer lm.Unlock() + + info := L.ToString(1) + lm.logs = append(lm.logs, info) + + return 0 +} + +// Push - golang端添加一行日志 +func (lm *LogModule) Push(log string) { + lm.Lock() + lm.logs = append(lm.logs, log) + lm.Unlock() +} + +func (lm *LogModule) Pop() string { + lm.Lock() + defer lm.Unlock() + + n := len(lm.logs) + if n == 0 { + return "" + } + x := lm.logs[n-1] + lm.logs = lm.logs[0 : n-1] + + return x +} + +func (lm *LogModule) Clean() { + lm.Lock() + lm.logs = []string{} + lm.Unlock() +} diff --git a/editor/src/constant/api.tsx b/editor/src/constant/api.tsx index 29cb5e2..318c424 100644 --- a/editor/src/constant/api.tsx +++ b/editor/src/constant/api.tsx @@ -41,7 +41,10 @@ const Api = { ConfigSystemInfo : "config.sys.info", ConfigSystemSet : "config.sys.set", ConfigGlobalInfo : "config.global.info", - ConfigGlobalSet : "config.global.set" + ConfigGlobalSet : "config.global.set", + + // + RuntimeInfo : "runtime.info", } diff --git a/editor/src/pages/edit/blackboard.tsx b/editor/src/pages/edit/blackboard.tsx index 5aa76b5..66a6078 100644 --- a/editor/src/pages/edit/blackboard.tsx +++ b/editor/src/pages/edit/blackboard.tsx @@ -6,18 +6,37 @@ import { useSelector } from 'react-redux' import Editor from "react-medium-editor"; import { RootState } from '@/models/store'; import "./blackboard.css"; +const { Post } = require("../../utils/request"); +import Api from "../../constant/api"; require("medium-editor/dist/css/medium-editor.css"); require("medium-editor/dist/css/themes/default.css"); - import ThemeType from '@/constant/constant'; +import { TaskTimer } from 'tasktimer'; const { TabPane } = Tabs; +const stdoutstr = async (botid: string) => { + let info = ""; + try { + const json = await Post(localStorage.remoteAddr, Api.RuntimeInfo, { ID: botid }); + if (json.Code == 200) { + info = json.Body.Msg; + } + } catch (err) { + console.error("Error:", err); + } + + if (info !== "") { + console.info("post runtime.info", info); + } + + return info; +}; + + export function Stdout() { - const { threadInfo } = useSelector((state: RootState) => state.debugInfoSlice); - const [runtimeerr, setRuntimeerr] = useState(""); const [change, setChange] = useState(String.raw` __ __ /\ \ /\ \__ @@ -30,47 +49,37 @@ export function Stdout() { \_/__/ v0.4.4 `) const { themeValue } = useSelector((state: RootState) => state.configSlice) + const { currentDebugBot } = useSelector((state: RootState) => state.treeSlice) useEffect(() => { - let msg = "" - let haveerr = false - - try { - threadInfo.forEach(element => { - msg += "Thread[" + element.number + "]\n" - - if (element.errmsg !== "") { - msg += element.errmsg - msg += "------------------------------\n" - haveerr = true - throw new Error(); - } - - let changemsg = "{}" - if (element.change !== "") { - changemsg = element.change - } - - try { - msg += JSON.stringify(JSON.parse(changemsg), null, 2) + "\n" - } catch (error) { - console.warn(error) - msg += changemsg + "\n" - } - - msg += "------------------------------\n" - }) - - if (msg !== "") { - setChange(msg) + + const newTimer = new TaskTimer(500); + newTimer.on('tick', async () => { + if (currentDebugBot === "") { + return + } + + let newmsg = await stdoutstr(currentDebugBot); + if (newmsg !== "") { + setChange(prev => { + let oldmsg = newmsg + "\n" + prev; + return oldmsg + }) + } + }); + newTimer.start(); + + return () => { + // 清理定时器 + if (newTimer) { + newTimer.stop(); } - } catch (err) { } - }, [threadInfo, themeValue]) + }, [themeValue, currentDebugBot]) return ( -
+
- +
); diff --git a/editor/src/utils/request.js b/editor/src/utils/request.js index 4961097..8922b6b 100644 --- a/editor/src/utils/request.js +++ b/editor/src/utils/request.js @@ -6,7 +6,7 @@ function Post(url, methon, formData) { method: "POST", mode: "cors", headers: { - "Content-Type": "application/x-www-form-urlencoded", + "Content-Type": "application/json", }, body: JSON.stringify(formData), })