Fix idle session breaking resize and input on reconnect
Two bugs introduced in the idle tracker pause commit: 1. handleOutput() short-circuited entirely when idle, skipping connector.OnData() — so terminal output never reached clients even after reconnecting. Fix: still call connector.OnData() during idle; only skip the expensive tracker.Feed(). 2. When a WebSocket client reconnects to an existing session, handleWebSocket never called UpdateConnector(), so the idle flag was never cleared and the tracker stayed paused. Fix: create a fresh connector and call session.UpdateConnector() on reconnect, which clears idle and rebuilds the tracker.
This commit is contained in:
@@ -791,17 +791,18 @@ t.Fatalf("replay mismatch: %q", got)
|
||||
s.MarkIdle()
|
||||
s.idleSince.Store(time.Now().Add(-idleTrackerThreshold - time.Second).UnixNano())
|
||||
|
||||
// Feed more output while idle — only replay should update
|
||||
s.handleOutput([]byte(" world"))
|
||||
if got := string(s.GetReplayBuffer()); got != "hello world" {
|
||||
t.Fatalf("replay should accumulate while idle: %q", got)
|
||||
}
|
||||
conn.mu.Lock()
|
||||
idleData := len(conn.data)
|
||||
conn.mu.Unlock()
|
||||
if idleData != 1 {
|
||||
t.Fatalf("connector should NOT receive data while idle, got %d calls", idleData)
|
||||
}
|
||||
// Feed more output while idle — replay and connector still receive data,
|
||||
// but the VT parser (tracker) is skipped.
|
||||
s.handleOutput([]byte(" world"))
|
||||
if got := string(s.GetReplayBuffer()); got != "hello world" {
|
||||
t.Fatalf("replay should accumulate while idle: %q", got)
|
||||
}
|
||||
conn.mu.Lock()
|
||||
idleData := len(conn.data)
|
||||
conn.mu.Unlock()
|
||||
if idleData != 2 {
|
||||
t.Fatalf("connector should still receive data while idle, got %d calls", idleData)
|
||||
}
|
||||
|
||||
// GetScreenSnapshot should rebuild tracker on-demand
|
||||
snap2 := s.GetScreenSnapshot()
|
||||
|
||||
@@ -154,6 +154,7 @@ func (s *DockerExecSession) handleOutput(data []byte) {
|
||||
if ts := s.idleSince.Load(); ts != 0 && time.Since(time.Unix(0, ts)) > idleTrackerThreshold {
|
||||
if len(filtered) > 0 {
|
||||
s.replay.Add(filtered)
|
||||
connector.OnData(filtered)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -515,6 +515,13 @@ func (s *LocalServer) handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||
session := s.sessionManager.GetSession(sessionID)
|
||||
if session != nil && session.IsRunning() {
|
||||
sessionCreated = true
|
||||
// Clear idle state so the output pipeline resumes fully
|
||||
connector := &localClientConnector{
|
||||
server: s,
|
||||
sessionID: sessionID,
|
||||
routeKey: routeKey,
|
||||
}
|
||||
session.UpdateConnector(connector)
|
||||
replay := daResponsePattern.ReplaceAll(session.GetReplayBuffer(), nil)
|
||||
if len(replay) > 0 {
|
||||
s.enqueueWSFrame(routeKey, websocket.BinaryMessage, replay)
|
||||
|
||||
@@ -146,9 +146,12 @@ func (s *TerminalSession) handleOutput(data []byte) {
|
||||
s.mu.Unlock()
|
||||
filtered = FilterUnsupportedModes(filtered)
|
||||
if ts := s.idleSince.Load(); ts != 0 && time.Since(time.Unix(0, ts)) > idleTrackerThreshold {
|
||||
// No client connected — only maintain the replay buffer.
|
||||
// No client connected — maintain replay buffer but skip VT parser.
|
||||
// Still call the connector so data flows if a client just reconnected
|
||||
// before MarkIdle was cleared.
|
||||
if len(filtered) > 0 {
|
||||
s.replay.Add(filtered)
|
||||
connector.OnData(filtered)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user