diff --git a/Tools/cli_client/debug_cli b/Tools/cli_client/debug_cli deleted file mode 100755 index c5c2255..0000000 Binary files a/Tools/cli_client/debug_cli and /dev/null differ diff --git a/Tools/cli_client/go.mod b/Tools/cli_client/go.mod deleted file mode 100644 index 61b5ee6..0000000 --- a/Tools/cli_client/go.mod +++ /dev/null @@ -1,17 +0,0 @@ -module marte_debug_cli - -go 1.25.7 - -require ( - github.com/gdamore/tcell/v2 v2.13.8 - github.com/rivo/tview v0.42.0 -) - -require ( - github.com/gdamore/encoding v1.0.1 // indirect - github.com/lucasb-eyer/go-colorful v1.3.0 // indirect - github.com/rivo/uniseg v0.4.7 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect -) diff --git a/Tools/cli_client/go.sum b/Tools/cli_client/go.sum deleted file mode 100644 index 648864c..0000000 --- a/Tools/cli_client/go.sum +++ /dev/null @@ -1,47 +0,0 @@ -github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw= -github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo= -github.com/gdamore/tcell/v2 v2.13.8 h1:Mys/Kl5wfC/GcC5Cx4C2BIQH9dbnhnkPgS9/wF3RlfU= -github.com/gdamore/tcell/v2 v2.13.8/go.mod h1:+Wfe208WDdB7INEtCsNrAN6O2m+wsTPk1RAovjaILlo= -github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= -github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/rivo/tview v0.42.0 h1:b/ftp+RxtDsHSaynXTbJb+/n/BxDEi+W3UfF5jILK6c= -github.com/rivo/tview v0.42.0/go.mod h1:cSfIYfhpSGCjp3r/ECJb+GKS7cGJnqV8vfjQPwoXyfY= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/Tools/cli_client/main.go b/Tools/cli_client/main.go deleted file mode 100644 index 18b97d1..0000000 --- a/Tools/cli_client/main.go +++ /dev/null @@ -1,498 +0,0 @@ -package main - -import ( - "encoding/binary" - "encoding/json" - "fmt" - "net" - "sort" - "strings" - "sync" - "time" - - "github.com/gdamore/tcell/v2" - "github.com/rivo/tview" -) - -// --- Models --- - -type Signal struct { - Name string `json:"name"` - ID uint32 `json:"id"` - Type string `json:"type"` -} - -type DiscoverResponse struct { - Signals []Signal `json:"Signals"` -} - -type TraceValue struct { - Value string - LastUpdate time.Time -} - -type AppState struct { - Signals map[string]Signal - IDToSignal map[uint32]string - ForcedSignals map[string]string - TracedSignals map[string]TraceValue - mu sync.RWMutex -} - -var state = AppState{ - Signals: make(map[string]Signal), - IDToSignal: make(map[uint32]string), - ForcedSignals: make(map[string]string), - TracedSignals: make(map[string]TraceValue), -} - -// --- UI Components --- - -var ( - app *tview.Application - forcedPane *tview.Table - tracedPane *tview.Table - statusPane *tview.TextView - frameworkLogPane *tview.TextView - cmdInput *tview.InputField - mainFlex *tview.Flex -) - -// logToStatus prints command output WITHOUT timestamp -func logToStatus(msg string) { - fmt.Fprintf(statusPane, "%s\n", msg) -} - -// logToFramework prints framework logs WITH timestamp -func logToFramework(level, msg string) { - color := "white" - switch level { - case "FatalError", "OSError", "ParametersError": - color = "red" - case "Warning": - color = "yellow" - case "Information": - color = "green" - case "Debug": - color = "blue" - } - fmt.Fprintf(frameworkLogPane, "[%s] [[%s]%s[-]] %s\n", time.Now().Format("15:04:05.000"), color, level, msg) -} - -// --- Network Logic --- - -var ( - tcpConn net.Conn - tcpMu sync.Mutex - responseChan = make(chan string, 2000) - connected = false -) - -func connectAndMonitor(addr string) { - for { - conn, err := net.Dial("tcp", addr) - if err != nil { - app.QueueUpdateDraw(func() { statusPane.SetText("[red]Connection failed, retrying...\n") }) - connected = false - time.Sleep(2 * time.Second) - continue - } - - if tc, ok := conn.(*net.TCPConn); ok { - tc.SetNoDelay(true) - } - - tcpConn = conn - connected = true - app.QueueUpdateDraw(func() { logToStatus("[green]Connected to DebugService (TCP 8080)") }) - - go discover() - - buf := make([]byte, 4096) - var line strings.Builder - for { - n, err := conn.Read(buf) - if err != nil { - app.QueueUpdateDraw(func() { logToStatus("[red]TCP Disconnected: " + err.Error()) }) - connected = false - break - } - - for i := 0; i < n; i++ { - if buf[i] == '\n' { - fullLine := strings.TrimSpace(line.String()) - line.Reset() - - if strings.HasPrefix(fullLine, "LOG ") { - parts := strings.SplitN(fullLine[4:], " ", 2) - if len(parts) == 2 { - app.QueueUpdateDraw(func() { logToFramework(parts[0], parts[1]) }) - } - } else if fullLine != "" { - select { - case responseChan <- fullLine: - default: - } - } - } else { - line.WriteByte(buf[i]) - } - } - } - tcpConn.Close() - time.Sleep(2 * time.Second) - } -} - -func startUDPListener(port int) { - addr, _ := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port)) - udpConn, err := net.ListenUDP("udp", addr) - if err != nil { - app.QueueUpdateDraw(func() { logToStatus(fmt.Sprintf("UDP Error: %v", err)) }) - return - } - defer udpConn.Close() - - buf := make([]byte, 2048) - for { - n, _, err := udpConn.ReadFromUDP(buf) - if err != nil || n < 20 { - continue - } - - magic := binary.LittleEndian.Uint32(buf[0:4]) - if magic != 0xDA7A57AD { - continue - } - - count := binary.LittleEndian.Uint32(buf[16:20]) - offset := 20 - now := time.Now() - for i := uint32(0); i < count; i++ { - if offset+8 > n { - break - } - id := binary.LittleEndian.Uint32(buf[offset : offset+4]) - size := binary.LittleEndian.Uint32(buf[offset+4 : offset+8]) - offset += 8 - if offset+int(size) > n { - break - } - data := buf[offset : offset+int(size)] - offset += int(size) - - state.mu.Lock() - if name, ok := state.IDToSignal[id]; ok { - valStr := "" - if size == 4 { - valStr = fmt.Sprintf("%d", binary.LittleEndian.Uint32(data)) - } else if size == 8 { - valStr = fmt.Sprintf("%d", binary.LittleEndian.Uint64(data)) - } else { - valStr = fmt.Sprintf("%X", data) - } - state.TracedSignals[name] = TraceValue{Value: valStr, LastUpdate: now} - } - state.mu.Unlock() - } - - app.QueueUpdateDraw(func() { updateTracedPane() }) - } -} - -func discover() { - tcpMu.Lock() - defer tcpMu.Unlock() - if !connected { - return - } - - app.QueueUpdateDraw(func() { logToStatus("Discovering signals...") }) - - // Drain old responses - for len(responseChan) > 0 { - <-responseChan - } - - fmt.Fprintf(tcpConn, "DISCOVER\n") - - var jsonBlock strings.Builder - timeout := time.After(5 * time.Second) - for { - select { - case line := <-responseChan: - if line == "OK DISCOVER" { - goto parsed - } - jsonBlock.WriteString(line) - case <-timeout: - app.QueueUpdateDraw(func() { logToStatus("[red]Discovery Timeout") }) - return - } - } -parsed: - var resp DiscoverResponse - if err := json.Unmarshal([]byte(jsonBlock.String()), &resp); err == nil { - state.mu.Lock() - state.IDToSignal = make(map[uint32]string) - for _, s := range resp.Signals { - state.Signals[s.Name] = s - state.IDToSignal[s.ID] = s.Name - } - state.mu.Unlock() - app.QueueUpdateDraw(func() { logToStatus(fmt.Sprintf("Discovered %d signals", len(resp.Signals))) }) - } -} - -// --- UI Updates --- - -func updateForcedPane() { - forcedPane.Clear() - forcedPane.SetCell(0, 0, tview.NewTableCell("Signal").SetTextColor(tcell.ColorYellow).SetAttributes(tcell.AttrBold)) - forcedPane.SetCell(0, 1, tview.NewTableCell("Value").SetTextColor(tcell.ColorYellow).SetAttributes(tcell.AttrBold)) - state.mu.RLock() - defer state.mu.RUnlock() - keys := make([]string, 0, len(state.ForcedSignals)) - for k := range state.ForcedSignals { - keys = append(keys, k) - } - sort.Strings(keys) - for i, k := range keys { - forcedPane.SetCell(i+1, 0, tview.NewTableCell(k)) - forcedPane.SetCell(i+1, 1, tview.NewTableCell(state.ForcedSignals[k]).SetTextColor(tcell.ColorGreen)) - } -} - -func updateTracedPane() { - tracedPane.Clear() - tracedPane.SetCell(0, 0, tview.NewTableCell("Signal").SetTextColor(tcell.ColorBlue).SetAttributes(tcell.AttrBold)) - tracedPane.SetCell(0, 1, tview.NewTableCell("Value").SetTextColor(tcell.ColorBlue).SetAttributes(tcell.AttrBold)) - tracedPane.SetCell(0, 2, tview.NewTableCell("Last Update").SetTextColor(tcell.ColorBlue).SetAttributes(tcell.AttrBold)) - state.mu.RLock() - defer state.mu.RUnlock() - keys := make([]string, 0, len(state.TracedSignals)) - for k := range state.TracedSignals { - keys = append(keys, k) - } - sort.Strings(keys) - for i, k := range keys { - tv := state.TracedSignals[k] - tracedPane.SetCell(i+1, 0, tview.NewTableCell(k)) - tracedPane.SetCell(i+1, 1, tview.NewTableCell(tv.Value)) - tracedPane.SetCell(i+1, 2, tview.NewTableCell(tv.LastUpdate.Format("15:04:05.000"))) - } -} - -// --- Command Handler --- - -func handleInput(text string) { - parts := strings.Fields(text) - if len(parts) == 0 { - return - } - cmd := strings.ToUpper(parts[0]) - args := parts[1:] - if !connected && cmd != "EXIT" && cmd != "QUIT" && cmd != "CLEAR" { - logToStatus("[red]Not connected to server") - return - } - - switch cmd { - case "LS": - path := "" - if len(args) > 0 { - path = args[0] - } - go func() { - tcpMu.Lock() - defer tcpMu.Unlock() - for len(responseChan) > 0 { - <-responseChan - } - fmt.Fprintf(tcpConn, "LS %s\n", path) - app.QueueUpdateDraw(func() { logToStatus(fmt.Sprintf("Listing nodes under %s...", path)) }) - timeout := time.After(2 * time.Second) - for { - select { - case line := <-responseChan: - if line == "OK LS" { - return - } - app.QueueUpdateDraw(func() { logToStatus(line) }) - case <-timeout: - app.QueueUpdateDraw(func() { logToStatus("[red]LS Timeout") }) - return - } - } - }() - case "FORCE": - if len(args) < 2 { - return - } - path, val := args[0], args[1] - go func() { - tcpMu.Lock() - defer tcpMu.Unlock() - fmt.Fprintf(tcpConn, "FORCE %s %s\n", path, val) - select { - case resp := <-responseChan: - app.QueueUpdateDraw(func() { - logToStatus("Server: " + resp) - state.mu.Lock() - state.ForcedSignals[path] = val - state.mu.Unlock() - updateForcedPane() - }) - case <-time.After(1 * time.Second): - app.QueueUpdateDraw(func() { logToStatus("[red]Server Timeout") }) - } - }() - case "UNFORCE": - if len(args) < 1 { - return - } - path := args[0] - go func() { - tcpMu.Lock() - defer tcpMu.Unlock() - fmt.Fprintf(tcpConn, "UNFORCE %s\n", path) - select { - case resp := <-responseChan: - app.QueueUpdateDraw(func() { - logToStatus("Server: " + resp) - state.mu.Lock() - delete(state.ForcedSignals, path) - state.mu.Unlock() - updateForcedPane() - }) - case <-time.After(1 * time.Second): - app.QueueUpdateDraw(func() { logToStatus("[red]Server Timeout") }) - } - }() - case "TRACE": - if len(args) < 1 { - return - } - path := args[0] - decim := "1" - if len(args) > 1 { - decim = args[1] - } - go func() { - tcpMu.Lock() - defer tcpMu.Unlock() - fmt.Fprintf(tcpConn, "TRACE %s 1 %s\n", path, decim) - select { - case resp := <-responseChan: - app.QueueUpdateDraw(func() { - logToStatus("Server: " + resp) - state.mu.Lock() - state.TracedSignals[path] = TraceValue{Value: "...", LastUpdate: time.Now()} - state.mu.Unlock() - updateTracedPane() - }) - case <-time.After(1 * time.Second): - app.QueueUpdateDraw(func() { logToStatus("[red]Server Timeout") }) - } - }() - case "UNTRACE": - if len(args) < 1 { - return - } - path := args[0] - go func() { - tcpMu.Lock() - defer tcpMu.Unlock() - fmt.Fprintf(tcpConn, "UNTRACE %s\n", path) - select { - case resp := <-responseChan: - app.QueueUpdateDraw(func() { - logToStatus("Server: " + resp) - state.mu.Lock() - delete(state.TracedSignals, path) - state.mu.Unlock() - updateTracedPane() - }) - case <-time.After(1 * time.Second): - app.QueueUpdateDraw(func() { logToStatus("[red]Server Timeout") }) - } - }() - case "DISCOVER": - go discover() - case "CLEAR": - statusPane.Clear() - frameworkLogPane.Clear() - case "EXIT", "QUIT": - app.Stop() - default: - logToStatus("Unknown command: " + cmd) - } -} - -func main() { - app = tview.NewApplication() - - forcedPane = tview.NewTable() - forcedPane.SetBorders(true) - forcedPane.SetTitle(" Forced Signals ") - forcedPane.SetBorder(true) - - tracedPane = tview.NewTable() - tracedPane.SetBorders(true) - tracedPane.SetTitle(" Traced Signals (Live) ") - tracedPane.SetBorder(true) - - statusPane = tview.NewTextView() - statusPane.SetDynamicColors(true) - statusPane.SetRegions(true) - statusPane.SetWordWrap(true) - statusPane.SetChangedFunc(func() { - statusPane.ScrollToEnd() - app.Draw() - }) - statusPane.SetTitle(" CLI Status / Command Output ") - statusPane.SetBorder(true) - - frameworkLogPane = tview.NewTextView() - frameworkLogPane.SetDynamicColors(true) - frameworkLogPane.SetRegions(true) - frameworkLogPane.SetWordWrap(true) - frameworkLogPane.SetChangedFunc(func() { - frameworkLogPane.ScrollToEnd() - app.Draw() - }) - frameworkLogPane.SetTitle(" MARTe2 Framework Logs ") - frameworkLogPane.SetBorder(true) - - cmdInput = tview.NewInputField() - cmdInput.SetLabel("marte_debug> ") - cmdInput.SetFieldWidth(0) - cmdInput.SetDoneFunc(func(key tcell.Key) { - if key == tcell.KeyEnter { - text := cmdInput.GetText() - if text != "" { - handleInput(text) - cmdInput.SetText("") - } - } - }) - - flexTop := tview.NewFlex() - flexTop.SetDirection(tview.FlexColumn) - flexTop.AddItem(forcedPane, 0, 1, false) - flexTop.AddItem(tracedPane, 0, 1, false) - flexTop.AddItem(statusPane, 0, 1, false) - - mainFlex = tview.NewFlex() - mainFlex.SetDirection(tview.FlexRow) - mainFlex.AddItem(flexTop, 0, 2, false) - mainFlex.AddItem(frameworkLogPane, 0, 1, false) - mainFlex.AddItem(cmdInput, 1, 0, true) - - go connectAndMonitor("127.0.0.1:8080") - go startUDPListener(8081) - - if err := app.SetRoot(mainFlex, true).EnableMouse(true).Run(); err != nil { - panic(err) - } -} diff --git a/Tools/cli_client/marte_debug_cli b/Tools/cli_client/marte_debug_cli deleted file mode 100755 index 76459a9..0000000 Binary files a/Tools/cli_client/marte_debug_cli and /dev/null differ