Files
nezha_domains/integration/agentcompat/internal/scenario/held_terminal_protocol.go
T
2026-07-20 04:51:20 +00:00

115 lines
2.8 KiB
Go

//go:build linux
package scenario
import (
"bytes"
"fmt"
"strconv"
"strings"
"github.com/nezhahq/nezha/integration/agentcompat/internal/client"
)
const heldTerminalProofLimit = 64 << 10
type heldTerminalProof struct {
marker string
buffer []byte
rows uint32
cols uint32
framed bool
closed error
frames uint64
bytes uint64
first client.FrameType
}
func newHeldTerminalProof(marker string) *heldTerminalProof {
return &heldTerminalProof{marker: marker}
}
func (proof *heldTerminalProof) Consume(frame client.Frame) {
if proof.Complete() || proof.closed != nil {
return
}
proof.frames++
proof.bytes += uint64(len(frame.Payload))
if proof.first == "" {
proof.first = frame.Type
}
proof.buffer = append(proof.buffer, frame.Payload...)
if len(proof.buffer) > heldTerminalProofLimit {
proof.buffer = proof.buffer[len(proof.buffer)-heldTerminalProofLimit:]
}
proof.consumeRecord()
}
func (proof *heldTerminalProof) consumeRecord() {
for {
start := bytes.IndexByte(proof.buffer, 0x1e)
if start < 0 {
proof.buffer = nil
return
}
proof.buffer = proof.buffer[start:]
endOffset := bytes.IndexByte(proof.buffer[1:], 0x1f)
if endOffset < 0 {
return
}
end := 1 + endOffset
record := string(proof.buffer[1:end])
proof.buffer = proof.buffer[end+1:]
recordMarker, sizeText, ok := strings.Cut(record, "|")
if !ok || recordMarker != proof.marker {
continue
}
values := strings.Fields(sizeText)
if len(values) != 2 {
continue
}
rows, rowsErr := strconv.ParseUint(values[0], 10, 32)
cols, colsErr := strconv.ParseUint(values[1], 10, 32)
if rowsErr != nil || colsErr != nil || rows == 0 || cols == 0 {
continue
}
proof.rows, proof.cols, proof.framed = uint32(rows), uint32(cols), true
return
}
}
func (proof *heldTerminalProof) Closed(err error) error {
proof.closed = err
return fmt.Errorf("terminal proof closed: %w", err)
}
func (proof *heldTerminalProof) Failure() error {
if proof.closed == nil {
return nil
}
return fmt.Errorf("terminal proof closed: %w", proof.closed)
}
func (proof *heldTerminalProof) Complete() bool {
return proof.framed && proof.rows == 43 && proof.cols == 132
}
func (proof *heldTerminalProof) Rows() uint32 { return proof.rows }
func (proof *heldTerminalProof) Columns() uint32 { return proof.cols }
func (proof *heldTerminalProof) FrameCount() uint64 { return proof.frames }
func (proof *heldTerminalProof) ByteCount() uint64 { return proof.bytes }
func (proof *heldTerminalProof) FirstFrameType() client.FrameType { return proof.first }
func heldTerminalCommand(marker string) string {
part := len(marker) / 2
return fmt.Sprintf("printf '\\036%%s%%s|' '%s' '%s'; stty size; printf '\\037'; read -r held_terminal_release; exit\n", marker[:part], marker[part:])
}
func hasHeldTerminalMarker(output []byte, marker string) bool {
return strings.Contains(string(output), marker)
}