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.MarkIdle()
|
||||||
s.idleSince.Store(time.Now().Add(-idleTrackerThreshold - time.Second).UnixNano())
|
s.idleSince.Store(time.Now().Add(-idleTrackerThreshold - time.Second).UnixNano())
|
||||||
|
|
||||||
// Feed more output while idle — only replay should update
|
// Feed more output while idle — replay and connector still receive data,
|
||||||
s.handleOutput([]byte(" world"))
|
// but the VT parser (tracker) is skipped.
|
||||||
if got := string(s.GetReplayBuffer()); got != "hello world" {
|
s.handleOutput([]byte(" world"))
|
||||||
t.Fatalf("replay should accumulate while idle: %q", got)
|
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.Lock()
|
||||||
conn.mu.Unlock()
|
idleData := len(conn.data)
|
||||||
if idleData != 1 {
|
conn.mu.Unlock()
|
||||||
t.Fatalf("connector should NOT receive data while idle, got %d calls", idleData)
|
if idleData != 2 {
|
||||||
}
|
t.Fatalf("connector should still receive data while idle, got %d calls", idleData)
|
||||||
|
}
|
||||||
|
|
||||||
// GetScreenSnapshot should rebuild tracker on-demand
|
// GetScreenSnapshot should rebuild tracker on-demand
|
||||||
snap2 := s.GetScreenSnapshot()
|
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 ts := s.idleSince.Load(); ts != 0 && time.Since(time.Unix(0, ts)) > idleTrackerThreshold {
|
||||||
if len(filtered) > 0 {
|
if len(filtered) > 0 {
|
||||||
s.replay.Add(filtered)
|
s.replay.Add(filtered)
|
||||||
|
connector.OnData(filtered)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -515,6 +515,13 @@ func (s *LocalServer) handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
session := s.sessionManager.GetSession(sessionID)
|
session := s.sessionManager.GetSession(sessionID)
|
||||||
if session != nil && session.IsRunning() {
|
if session != nil && session.IsRunning() {
|
||||||
sessionCreated = true
|
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)
|
replay := daResponsePattern.ReplaceAll(session.GetReplayBuffer(), nil)
|
||||||
if len(replay) > 0 {
|
if len(replay) > 0 {
|
||||||
s.enqueueWSFrame(routeKey, websocket.BinaryMessage, replay)
|
s.enqueueWSFrame(routeKey, websocket.BinaryMessage, replay)
|
||||||
|
|||||||
@@ -146,9 +146,12 @@ func (s *TerminalSession) handleOutput(data []byte) {
|
|||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
filtered = FilterUnsupportedModes(filtered)
|
filtered = FilterUnsupportedModes(filtered)
|
||||||
if ts := s.idleSince.Load(); ts != 0 && time.Since(time.Unix(0, ts)) > idleTrackerThreshold {
|
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 {
|
if len(filtered) > 0 {
|
||||||
s.replay.Add(filtered)
|
s.replay.Add(filtered)
|
||||||
|
connector.OnData(filtered)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user