From 42d27c06472fabf80ef82aaf4587a9abb5e1eb1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Monta=C3=B1es=20Ojados?= Date: Mon, 19 Jan 2026 16:32:57 +0100 Subject: [PATCH] fix: Implement proactive packet flushing based on Content-Length to resolve UI update lag --- internal/capture/capturer.go | 30 ++++++++++++++++++++++++++++-- internal/capture/local.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/internal/capture/capturer.go b/internal/capture/capturer.go index 8efa0c5..a7e4f05 100644 --- a/internal/capture/capturer.go +++ b/internal/capture/capturer.go @@ -4,6 +4,7 @@ import ( "bufio" "fmt" "io" + "strconv" "strings" "sync" "time" @@ -111,6 +112,7 @@ func (c *Capturer) processStream(r io.Reader) { var buffer strings.Builder inSIPMessage := false var msgNetInfo *NetInfo + contentLength := -1 for scanner.Scan() { c.mu.Lock() @@ -149,14 +151,38 @@ func (c *Capturer) processStream(r io.Reader) { } inSIPMessage = true + contentLength = -1 // Reset } if inSIPMessage { buffer.WriteString(line) buffer.WriteString("\r\n") - // Detect end of SIP message (double CRLF or content complete) - // This is simplified - real implementation would track Content-Length + // Check for Content-Length + lowerLine := strings.ToLower(line) + if strings.HasPrefix(lowerLine, "content-length:") || strings.HasPrefix(lowerLine, "l:") { + parts := strings.Split(line, ":") + if len(parts) >= 2 { + val := strings.TrimSpace(parts[1]) + if val != "" { + if cl, err := strconv.Atoi(val); err == nil { + contentLength = cl + } + } + } + } + + // Check for end of headers (empty line) + if line == "" { + // If Content-Length is 0 (or not found, treating as 0) + // Flush immediately + if contentLength <= 0 { + c.parseAndEmit(buffer.String(), msgNetInfo) + buffer.Reset() + inSIPMessage = false + contentLength = -1 + } + } } } diff --git a/internal/capture/local.go b/internal/capture/local.go index fdcc90c..c9b6778 100644 --- a/internal/capture/local.go +++ b/internal/capture/local.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "os/exec" + "strconv" "strings" "sync" @@ -133,6 +134,7 @@ func (c *LocalCapturer) processStream(r io.Reader) { var buffer strings.Builder inSIPMessage := false var msgNetInfo *NetInfo + contentLength := -1 for scanner.Scan() { c.mu.Lock() @@ -192,11 +194,38 @@ func (c *LocalCapturer) processStream(r io.Reader) { } inSIPMessage = true + contentLength = -1 // Reset for new message } if inSIPMessage { buffer.WriteString(line) buffer.WriteString("\r\n") + + // Check for Content-Length + lowerLine := strings.ToLower(line) + if strings.HasPrefix(lowerLine, "content-length:") || strings.HasPrefix(lowerLine, "l:") { + parts := strings.Split(line, ":") + if len(parts) >= 2 { + val := strings.TrimSpace(parts[1]) + if val != "" { + if cl, err := strconv.Atoi(val); err == nil { + contentLength = cl + } + } + } + } + + // Check for end of headers (empty line) + if line == "" { + // If Content-Length is 0 (or not found, treating as 0 for safety in this context usually 0 for BYE/ACK) + // Flush immediately + if contentLength <= 0 { + c.parseAndEmit(buffer.String(), msgNetInfo) + buffer.Reset() + inSIPMessage = false + contentLength = -1 + } + } } }