From 0620cb5c2c90c42595b44d8084bf5bb1c8e870fa Mon Sep 17 00:00:00 2001 From: llaoj Date: Mon, 12 Dec 2022 09:19:30 +0800 Subject: [PATCH 1/2] For the brevity of the code, I changed the print format of arguments. --- webtty/webtty.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/webtty/webtty.go b/webtty/webtty.go index e5b39b6..daa57b3 100644 --- a/webtty/webtty.go +++ b/webtty/webtty.go @@ -93,17 +93,13 @@ func (wt *WebTTY) Run(ctx context.Context) error { errs <- func() error { buffer := make([]byte, wt.bufferSize) var line string - arguments, err := json.Marshal(wt.arguments) - if err != nil { - return err - } for { n, err := wt.masterConn.Read(buffer) if err != nil { return ErrMasterClosed } - err = wt.handleMasterReadEvent(buffer[:n], &line, arguments) + err = wt.handleMasterReadEvent(buffer[:n], &line) if err != nil { return err } @@ -172,7 +168,7 @@ func (wt *WebTTY) masterWrite(data []byte) error { return nil } -func (wt *WebTTY) handleMasterReadEvent(data []byte, line *string, argument []byte) error { +func (wt *WebTTY) handleMasterReadEvent(data []byte, line *string) error { if len(data) == 0 { return errors.New("unexpected zero length read from master") } @@ -198,7 +194,7 @@ func (wt *WebTTY) handleMasterReadEvent(data []byte, line *string, argument []by // 13(ASCII) means carriage return(CR) // it is the end of a line if decodedBuffer[n-1] == 13 { - log.Printf("[write-log] %s %s\n", argument, *line) + log.Printf("[write-log] %v %s\n", wt.arguments, *line) *line = "" } } From 8450aa5ee231c769a689dc5fc94b5e99ef5edbed Mon Sep 17 00:00:00 2001 From: llaoj Date: Tue, 13 Dec 2022 13:52:15 +0800 Subject: [PATCH 2/2] control sequenes --- README.md | 5 ++- utils/log.go | 109 ++++++++++++++++++++++++++++----------------------- 2 files changed, 62 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index 93253b7..021f808 100644 --- a/README.md +++ b/README.md @@ -175,8 +175,9 @@ visit `http://127.0.0.1:8080/?arg=without-istio&arg=sleep-7b6d569576-57sjq&arg=s ``` ... -2022/11/13 10:48:12 [write-log] {"arg":["without-istio","sleep-7b6d569576-57sjq","sleep","21001713"]} lsCR -2022/11/13 10:48:14 [write-log] {"arg":["without-istio","sleep-7b6d569576-57sjq","sleep","21001713"]} pwdCR +2022/12/13 13:36:46 [write-log] map[arg:[without-istio sleep-7b6d569576-8nz7t sleep 21001713]] ls[CR] +2022/12/13 13:37:25 [write-log] map[arg:[without-istio sleep-7b6d569576-8nz7t sleep 21001713]] echo[SPACE]hello[SPACE]world;[CR] +2022/12/13 13:47:00 [write-log] map[arg:[without-istio sleep-7b6d569576-8nz7t sleep 21001713]] [CUU][CR] ... ``` diff --git a/utils/log.go b/utils/log.go index ca710a7..f606693 100644 --- a/utils/log.go +++ b/utils/log.go @@ -1,8 +1,11 @@ package utils -import "fmt" +import ( + "fmt" + "regexp" +) -var CtrlChar = map[byte]string{ +var ControlCodes = map[byte]string{ 0: "NUL", 1: "SOH", 2: "STX", @@ -39,67 +42,73 @@ var CtrlChar = map[byte]string{ 127: "DEL", } -var CtrlCharGroup = map[string]string{ - "1B5B41": "UP", - "1B5B42": "DOWN", - "1B5B43": "RIGHT", - "1B5B44": "LEFT", - - // shell control codes - // codes[0]+codes[1]+codes[n-1] - // for example: - // [1B(ESC) 5B([) 32(2) 3B(;) 35(5) 52(R)]: row 2 col 5 - // [1B(ESC) 5B([) 31(1) 30(0) 3B(;) 35(5) 52(R)]: row 10 col 5 - // [1B(ESC) 5B([) 32(2) 32(2) 3B(;) 35(5) 52(R)]: row 22 col 5 - "1B5B52": "", - - // maybe there will be more control char group - // ... +// https://en.wikipedia.org/wiki/ANSI_escape_code +// https://xtermjs.org/docs/api/vtfeatures/ +var ControlSequences = map[string]string{ + // Cursor Up + "ESC[A": "CUU", + // Cursor Down + "ESC[B": "CUD", + // Cursor Forward + "ESC[C": "CUF", + // Cursor Back + "ESC[D": "CUB", } -func FormatWriteLog(codes []byte, line *string) { - n := len(codes) - // when user uses the keyboard arrow keys - // arrow keys are combination of 3 ASCII codes - if n == 3 { - if str, exist := ASCIIGroupToStr(fmt.Sprintf("%X", codes)); exist { - *line += str - return - } - } - // for some shells - // they will automatically send some control characters - // after typing the command and pressing Enter - // which indicate the current row and column. - if n >= 6 { - if str, exist := ASCIIGroupToStr(fmt.Sprintf("%X", []byte{codes[0], codes[1], codes[n-1]})); exist { - *line += str - return - } - } - - str := ASCIIToStr(codes) - *line += str - - return +var ControlSequencePatterns = map[string]string{ + // Device Status Report + // Reports the cursor position (CPR) by transmitting `ESC[n;mR`, where n is the row and m is the column. + "^ESC\\[\\d+;\\d+R$": "", } -func ASCIIToStr(codes []byte) (str string) { +func ControlCodesToStr(codes []byte) (str string) { for _, code := range codes { - if value, ok := CtrlChar[code]; ok { + if value, ok := ControlCodes[code]; ok { str += value } else { str += string(code) } } - return } -func ASCIIGroupToStr(group string) (string, bool) { - if value, ok := CtrlCharGroup[group]; ok { - return value, true +func ControlCodesToEscapedStr(codes []byte) (str string) { + for _, code := range codes { + if value, ok := ControlCodes[code]; ok { + str += fmt.Sprintf("[%s]", value) + } else if code == 91 || code == 92 || code == 93 { + // escaping [ ] \ + str += fmt.Sprintf("\\%s", string(code)) + } else { + str += string(code) + } + } + return +} + +func ControlSequenceToStr(codes []byte) (string, bool) { + sequence := ControlCodesToStr(codes) + for key, value := range ControlSequences { + if key == sequence { + return fmt.Sprintf("[%s]", value), true + } } - return "", false + for key, value := range ControlSequencePatterns { + if regexp.MustCompile(key).Match([]byte(sequence)) { + return value, true + } + } + return sequence, false +} + +func FormatWriteLog(codes []byte, line *string) { + n := len(codes) + if n >= 3 { + if str, exists := ControlSequenceToStr(codes); exists { + *line += str + return + } + } + *line += ControlCodesToEscapedStr(codes) }