Skip to content

Commit bf99a64

Browse files
committed
chore: don't cache events & handle all events in single read event
1 parent 04b9740 commit bf99a64

File tree

3 files changed

+107
-261
lines changed

3 files changed

+107
-261
lines changed

escape.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package main
22

33
var (
4-
EscapeWindowChangePrefix = []byte("\x1B[8;")
5-
EscapeWindowChangePrefixLen = len(EscapeWindowChangePrefix)
6-
EscapeWindowChangeSuffix = byte('t') // We only require this so it has been hard-encoded (compare func and length)
4+
EscapeWindowChangePrefix = []byte("\x1B[8;")
5+
EscapeWindowChangeSuffix = byte('t') // We only require this so it has been hard-encoded (compare func and length)
76
)

pipe.go

Lines changed: 50 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -57,198 +57,86 @@ func procWindowChangeEvent(eventPayload string, windowResize func(h int, w int)
5757

5858
func inPipe(from io.Reader, to io.Writer, windowResize func(h int, w int) error) error {
5959
inBuf := make([]byte, DefaultBufferSize)
60-
eventBuf := make([]byte, DefaultBufferSize)
61-
62-
evSize := 0
6360

6461
for {
6562
// Receive data
6663
n, err := from.Read(inBuf)
6764
if err != nil {
6865
if errors.Is(err, io.EOF) {
69-
if evSize > 0 {
70-
// Still contain event cache data, send them all
71-
_, err = to.Write(eventBuf[:evSize])
72-
if err != nil {
73-
return fmt.Errorf("failed to pipe to stdin: %w", err)
74-
}
75-
}
7666
break
7767
} else {
7868
return fmt.Errorf("failed to read from stdin: %w", err)
7969
}
8070
}
8171

82-
// Set start index
83-
start := 0
84-
if evSize > 0 {
85-
// Last loop remains unprocessed data, continue to process
86-
if evSize < EscapeWindowChangePrefixLen {
87-
// Prefix not matched, start to match prefix
88-
for ; start+evSize <= EscapeWindowChangePrefixLen; start++ { // Start from the first byte after \x1B
89-
eventBuf[start+evSize] = inBuf[start]
90-
if inBuf[start] != EscapeWindowChangePrefix[start+evSize-1] {
91-
// Mismatch
92-
start = 0
93-
break
94-
}
95-
}
72+
dataBuf := inBuf[:n]
9673

97-
if start == 0 { // Mismatch
98-
// Unable to handle this, send buffered event data to server
99-
_, err = to.Write(eventBuf[:evSize])
100-
if err != nil {
101-
return fmt.Errorf("failed to pipe to stdin: %w", err)
102-
}
103-
evSize = 0 // reset
104-
}
105-
}
74+
for { // Process all events in a single input event (latest one overwrites all before)
75+
// Check if event exists
76+
dataLen := len(dataBuf)
77+
eventStartIndex := bytes.Index(dataBuf, EscapeWindowChangePrefix)
10678

107-
if evSize > 0 {
108-
// Prefix match, start receiving event bytes till match suffix
109-
for ; start < n; start++ {
110-
eventBuf[start+evSize] = inBuf[start]
111-
if inBuf[start] == EscapeWindowChangeSuffix {
112-
break
113-
}
114-
}
115-
116-
if start >= n {
117-
// Message incomplete, save it and wait for next loop
118-
evSize += start
119-
continue
120-
}
121-
122-
// else: suffix match, message complete
123-
// Maybe contain some incomplete event fragments, so go reversely to find if any prefix match
124-
eventPayloadSliceFrom := EscapeWindowChangePrefixLen // discard prefix
125-
eventPayload := eventBuf[:evSize+start] // discard suffix
126-
eventPrefixLastIndex := bytes.LastIndex(eventPayload, EscapeWindowChangePrefix)
127-
if eventPrefixLastIndex != 0 {
128-
// Include invalid events
129-
130-
// Send invalid events as raw content to writer
131-
_, err = to.Write(eventPayload[:eventPrefixLastIndex])
132-
if err != nil {
133-
return fmt.Errorf("failed to pipe to stdin: %w", err)
134-
}
135-
136-
// Slice from new location
137-
eventPayloadSliceFrom = eventPrefixLastIndex + EscapeWindowChangePrefixLen
79+
if eventStartIndex == -1 {
80+
// No event, just pipe normally
81+
_, err = to.Write(dataBuf[:dataLen])
82+
if err != nil {
83+
return fmt.Errorf("failed to pipe to stdin: %w", err)
13884
}
139-
err = procWindowChangeEvent(string(eventPayload[eventPayloadSliceFrom:]), windowResize)
85+
break // Proceed to next loop
86+
} else if eventStartIndex > 0 { // 0 means nothing to send
87+
// Send bytes before event
88+
_, err = to.Write(dataBuf[:eventStartIndex])
14089
if err != nil {
141-
// Unable to handle this, send buffered event data to server
142-
_, err = to.Write(eventBuf[eventPrefixLastIndex:evSize])
143-
if err != nil {
144-
return fmt.Errorf("failed to pipe to stdin: %w", err)
145-
}
146-
start = 0 // reset
147-
} else {
148-
start += 1 // Skip suffix
90+
return fmt.Errorf("failed to pipe to stdin: %w", err)
14991
}
150-
151-
evSize = 0 // reset
15292
}
153-
}
154-
155-
i := start
156-
157-
// Check byte by byte
158-
for ; i < n; i++ {
159-
if inBuf[i] == EscapeWindowChangePrefix[0] { // ESC for ANSI escape sequences
160-
break
161-
}
162-
}
163-
164-
if i >= n {
165-
// No event, just pipe normally
166-
_, err = to.Write(inBuf[start:n])
167-
if err != nil {
168-
return fmt.Errorf("failed to pipe to stdin: %w", err)
169-
}
170-
continue // Proceed to next loop
171-
}
172-
173-
// Otherwise: event caused early end
174-
_, err = to.Write(inBuf[start:i]) // pipe data before event
175-
if err != nil {
176-
return fmt.Errorf("failed to pipe to stdin: %w", err)
177-
}
17893

179-
// Match prefix
180-
for evSize = 0; (i+evSize < n) && (evSize < EscapeWindowChangePrefixLen); evSize++ { // Start from the first byte
181-
eventBuf[evSize] = inBuf[i+evSize]
182-
if inBuf[i+evSize] != EscapeWindowChangePrefix[evSize] {
183-
// Mismatch
184-
evSize = 0
185-
break
186-
}
187-
}
94+
// Match suffix
95+
eventEndIndex := eventStartIndex + len(EscapeWindowChangePrefix)
18896

189-
if evSize == 0 { // Mismatch
190-
// Unable to handle this, send to server
191-
_, err = to.Write(inBuf[i:n])
192-
if err != nil {
193-
return fmt.Errorf("failed to pipe to stdin: %w", err)
97+
// else: prefix all match, extract all bytes into event buffer till match suffix
98+
for ; eventEndIndex < dataLen; eventEndIndex++ {
99+
if dataBuf[eventEndIndex] == EscapeWindowChangeSuffix {
100+
break
101+
}
194102
}
195-
continue // Proceed to next loop
196-
}
197103

198-
if i+evSize >= n {
199-
// Message incomplete, save it and wait for next loop
200-
continue
201-
}
202-
203-
// else: prefix all match, extract all bytes into event buffer till match suffix
204-
for ; i+evSize < n; evSize++ {
205-
eventBuf[evSize] = inBuf[i+evSize]
206-
if inBuf[i+evSize] == EscapeWindowChangeSuffix {
207-
break
104+
if eventEndIndex >= dataLen {
105+
// Incomplete event, just pipe normally
106+
_, err = to.Write(dataBuf[eventStartIndex:])
107+
if err != nil {
108+
return fmt.Errorf("failed to pipe to stdin: %w", err)
109+
}
110+
break // Proceed to next loop
208111
}
209-
}
210112

211-
if i+evSize >= n {
212-
// Message incomplete, save it and wait for next loop
213-
continue
214-
}
113+
// else: event all extracted! time to analyse
114+
// Maybe contain some incomplete event fragments, so go reversely to find if any prefix match
115+
eventPayload := dataBuf[eventStartIndex:eventEndIndex] // discard suffix
116+
eventPrefixLastIndex := bytes.LastIndex(eventPayload, EscapeWindowChangePrefix)
117+
if eventPrefixLastIndex > 0 {
118+
// Include invalid events
215119

216-
// else: event all extracted! time to analyse
217-
// Maybe contain some incomplete event fragments, so go reversely to find if any prefix match
218-
eventPayloadSliceFrom := EscapeWindowChangePrefixLen // discard prefix
219-
eventPayload := eventBuf[:evSize] // discard suffix
220-
eventPrefixLastIndex := bytes.LastIndex(eventPayload, EscapeWindowChangePrefix)
221-
if eventPrefixLastIndex != 0 {
222-
// Include invalid events
223-
224-
// Send invalid events as raw content to writer
225-
_, err = to.Write(eventPayload[:eventPrefixLastIndex])
226-
if err != nil {
227-
return fmt.Errorf("failed to pipe to stdin: %w", err)
120+
// Send invalid events as raw content
121+
_, err = to.Write(eventPayload[:eventPrefixLastIndex])
122+
if err != nil {
123+
return fmt.Errorf("failed to pipe to stdin: %w", err)
124+
}
228125
}
229126

230-
// Slice from new location
231-
eventPayloadSliceFrom = eventPrefixLastIndex + EscapeWindowChangePrefixLen
232-
}
233-
err = procWindowChangeEvent(string(eventPayload[eventPayloadSliceFrom:]), windowResize)
234-
if err != nil {
235-
// Something is wrong, we can't handle this event, so send without processing
236-
evSize = 0 // reset
237-
_, err = to.Write(inBuf[i+eventPrefixLastIndex : n]) // Send everything
238-
if err != nil {
239-
return fmt.Errorf("failed to proc window change event: %w", err)
127+
// Process event
128+
if err = procWindowChangeEvent(string(eventPayload[eventPrefixLastIndex+len(EscapeWindowChangePrefix):]), windowResize); err != nil {
129+
// Something is wrong, we can't handle this event, so send without processing
130+
_, err = to.Write(dataBuf[eventStartIndex+eventPrefixLastIndex:]) // Send everything
131+
if err != nil {
132+
return fmt.Errorf("failed to proc window change event: %w", err)
133+
}
134+
break // Proceed to next loop
240135
}
241-
continue // Proceed to next loop
242-
}
243136

244-
// Send remain bytes
245-
_, err = to.Write(inBuf[i+evSize+1 : n])
246-
if err != nil {
247-
return fmt.Errorf("failed to pipe to stdin: %w", err)
137+
// Continue to process remain bytes
138+
dataBuf = dataBuf[eventEndIndex+1:]
248139
}
249-
250-
// Reset event size as already processed
251-
evSize = 0
252140
}
253141

254142
return nil

0 commit comments

Comments
 (0)