diff --git a/code/internal/server/ws.go b/code/internal/server/ws.go index b56d5d8..299ba3d 100644 --- a/code/internal/server/ws.go +++ b/code/internal/server/ws.go @@ -44,6 +44,8 @@ func (s *Server) handleConsoleWS(c *gin.Context) { idx = 1 } + log.Printf("WS[%s]: connected", sessionNum) + session := s.console.getSession(idx) // Wait for PTY session to be available (it gets set when a command is executed) @@ -52,12 +54,13 @@ func (s *Server) handleConsoleWS(c *gin.Context) { session.mu.Unlock() if ptySess == nil { - // No active PTY — send message and wait - conn.WriteMessage(websocket.TextMessage, []byte("\r\n\033[33m[Nema aktivne sesije. Pokrenite komandu.]\033[0m\r\n")) + log.Printf("WS[%s]: no PTY yet, polling...", sessionNum) + conn.WriteMessage(websocket.TextMessage, []byte("\r\n\033[33m[Čekam pokretanje sesije...]\033[0m\r\n")) - // Poll for session to start - ticker := time.NewTicker(500 * time.Millisecond) + // Poll for session to start (up to 30s) + ticker := time.NewTicker(300 * time.Millisecond) defer ticker.Stop() + timeout := time.After(30 * time.Second) for { select { case <-ticker.C: @@ -65,25 +68,42 @@ func (s *Server) handleConsoleWS(c *gin.Context) { ptySess = session.ptySess session.mu.Unlock() if ptySess != nil { + log.Printf("WS[%s]: PTY found after polling", sessionNum) goto connected } + case <-timeout: + log.Printf("WS[%s]: timeout waiting for PTY", sessionNum) + conn.WriteMessage(websocket.TextMessage, []byte("\r\n\033[31m[Timeout — sesija nije pokrenuta]\033[0m\r\n")) + return case <-c.Request.Context().Done(): + log.Printf("WS[%s]: client disconnected while polling", sessionNum) return } } } connected: + log.Printf("WS[%s]: subscribing to PTY", sessionNum) subID := fmt.Sprintf("ws-%d", time.Now().UnixNano()) outputCh := ptySess.Subscribe(subID) defer ptySess.Unsubscribe(subID) // Send buffered output for reconnect buffered := ptySess.GetBuffer() + log.Printf("WS[%s]: sending buffer (%d bytes)", sessionNum, len(buffered)) if len(buffered) > 0 { conn.WriteMessage(websocket.BinaryMessage, buffered) } + // Check if already done + select { + case <-ptySess.Done(): + log.Printf("WS[%s]: PTY already done, sending buffer only", sessionNum) + conn.WriteMessage(websocket.TextMessage, []byte("\r\n\033[33m[Sesija završena]\033[0m\r\n")) + return + default: + } + // Serialized write channel writeCh := make(chan []byte, 256) writeDone := make(chan struct{}) @@ -109,11 +129,11 @@ connected: // Watch for process exit go func() { <-ptySess.Done() + log.Printf("WS[%s]: PTY process exited", sessionNum) select { case writeCh <- []byte("\r\n\033[33m[Sesija završena]\033[0m\r\n"): default: } - // Give browser time to receive the message, then close time.Sleep(500 * time.Millisecond) conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "done")) @@ -124,7 +144,7 @@ connected: _, msg, err := conn.ReadMessage() if err != nil { if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure) { - log.Printf("WebSocket read error: %v", err) + log.Printf("WS[%s]: read error: %v", sessionNum, err) } break } @@ -133,18 +153,19 @@ connected: var resize wsResizeMsg if json.Unmarshal(msg, &resize) == nil && resize.Type == "resize" && resize.Cols > 0 && resize.Rows > 0 { if err := ptySess.Resize(resize.Rows, resize.Cols); err != nil { - log.Printf("PTY resize error: %v", err) + log.Printf("WS[%s]: resize error: %v", sessionNum, err) } continue } // Regular keyboard input → PTY if _, err := ptySess.WriteInput(msg); err != nil { - log.Printf("PTY write error: %v", err) + log.Printf("WS[%s]: PTY write error: %v", sessionNum, err) break } } close(writeCh) <-writeDone + log.Printf("WS[%s]: disconnected", sessionNum) } diff --git a/code/web/templates/console.html b/code/web/templates/console.html index 0b77342..c75cb9c 100644 --- a/code/web/templates/console.html +++ b/code/web/templates/console.html @@ -42,10 +42,6 @@
-