io

package
v0.25.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2026 License: Apache-2.0 Imports: 6 Imported by: 1

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewContextReader

func NewContextReader(ctx context.Context, r io.Reader) io.Reader

Types

type MultiWriter

type MultiWriter struct {
	// contains filtered or unexported fields
}

MultiWriter is a concurrent safe writer that allows appending/removing writers. Newly appended writers get the last write to preserve last output.

Attached writers are tracked by identity, so they must be comparable; see checkRemovable, which is how Append enforces it. NewMultiWriter does not, because it cannot report the error, so prefer Append.

func NewMultiWriter

func NewMultiWriter(bufferSize int, writers ...io.Writer) *MultiWriter

func (*MultiWriter) Append

func (t *MultiWriter) Append(writers ...io.Writer) error

func (*MultiWriter) Remove

func (t *MultiWriter) Remove(writers ...io.Writer)

func (*MultiWriter) Write

func (t *MultiWriter) Write(p []byte) (int, error)

Write fans p out to every attached writer. It always reports success.

Two things here are deliberate, and both were bugs.

The membership lock is released before any writer is written to. Holding one lock for both jobs made Append and Remove wait on whatever the slowest attached writer was doing, and a guest that stops reading its SSH channel blocks in Write indefinitely once the channel window fills. That wedged the host: HandleSession removes its writer on the way out, so Remove blocked, HandleSession never returned, and the client-left event it emits on the way out was never sent. Writes are still serialized among themselves, by writeMu, because concurrent producers must not interleave in a writer or race one that is not concurrency safe.

A failing writer is dropped rather than reported. This is a broadcast to whoever is attached, and the producer is the host's pty: returning an error aborted the io.Copy feeding it, which ended the command and tore down the whole session. One guest losing its connection at the wrong moment must not take the session with it. Errors used to abandon the rest of the slice too, so a broken guest silenced everyone attached after it.

A writer removed between the snapshot and the write still receives this one write. That is harmless: it is a session on its way out.

Still outstanding: the writes are serial, so a guest that has stopped reading holds up the fan-out for everyone until its write returns. Fixing that needs per-writer buffering, so that a guest which cannot keep up is dropped rather than allowed to slow the session down. Tracked in owenthereal/upterm#524.

type TerminalQueryFilter added in v0.21.0

type TerminalQueryFilter struct {
	// contains filtered or unexported fields
}

TerminalQueryFilter wraps an io.Writer and filters out terminal query sequences from the output. This prevents queries sent by the host's shell from reaching connected clients, whose terminals would otherwise respond and pollute the PTY input.

Filtered queries include:

  • OSC 10/11/12 queries (foreground/background/cursor color): ESC ] N ; ? BEL/ST
  • CSI 5 n (device status request)
  • CSI 6 n (cursor position request)
  • CSI c / CSI 0 c (primary device attributes)
  • CSI > c / CSI > 0 c (secondary device attributes)
  • CSI = c / CSI = 0 c (tertiary device attributes)

func NewTerminalQueryFilter added in v0.21.0

func NewTerminalQueryFilter(w io.Writer) *TerminalQueryFilter

NewTerminalQueryFilter creates a filter that removes terminal query sequences from output before writing to the underlying writer.

func (*TerminalQueryFilter) Write added in v0.21.0

func (f *TerminalQueryFilter) Write(p []byte) (int, error)

Write filters terminal query sequences from p and writes the result to the underlying writer. Returns len(p) on success to indicate all input bytes were processed. On error, returns 0 because the filtered output is written atomically (all or nothing) and input bytes don't map 1:1 to output bytes due to filtering.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL