Documentation
¶
Overview ¶
Package store keeps captured flows for the lifetime of the daemon, entirely in memory: a bounded ring of flow snapshots (the hot path), a byte-budgeted content-addressed blob cache for bodies, a per-flow WebSocket message log, the session registry, and the filter matching used by every list/search endpoint. Nothing is written to disk; every daemon start begins empty.
Index ¶
- Constants
- Variables
- func BodyText(ref flow.BodyRef, bodies BodyFunc) (string, bool)
- func DecodeBody(encoding string, b []byte, limit int64) ([]byte, error)
- func Flags(f *flow.Flow) []string
- func FormatBytes(n int64) string
- func FormatDuration(d time.Duration) string
- func Hash(b []byte) string
- func IsLLMHost(host string) bool
- func IsTextual(class string) bool
- func MatchClient(want, addr string) bool
- func ParseTime(s string, now time.Time) (time.Time, bool)
- func Query(m *Mem, filter api.FlowFilter, limit int, now time.Time, bodies BodyFunc) api.FlowList
- func Row(f *flow.Flow) api.FlowRow
- func StatusMatcher(spec string) func(int) bool
- func TypeClass(ct string) string
- type Blobs
- type BodyFunc
- type Matcher
- type Mem
- func (m *Mem) Cap() int
- func (m *Mem) Clear()
- func (m *Mem) Count(match func(*flow.Flow) bool) int
- func (m *Mem) Delete(match func(*flow.Flow) bool) int
- func (m *Mem) Each(fn func(*flow.Flow) bool)
- func (m *Mem) Get(id flow.ID) (*flow.Flow, bool)
- func (m *Mem) Len() int
- func (m *Mem) Newest() flow.ID
- func (m *Mem) Total() int64
- func (m *Mem) Upsert(f *flow.Flow)
- type MemBlobs
- type Sessions
- type WSLog
Constants ¶
const DefaultDecodeLimit = 8 << 20
DefaultDecodeLimit bounds DecodeBody output when limit is 0.
const DefaultSessionName = "default"
DefaultSessionName is the name of the session every daemon starts in.
const SearchTextCap = 256 << 10
SearchTextCap bounds how many decoded body bytes a text search (Q) looks at per body.
Variables ¶
var ErrCurrent = errors.New("store: cannot delete the current session")
ErrCurrent is returned by Delete for the current session.
var ErrDecodeLimit = errors.New("store: decoded body exceeds limit")
ErrDecodeLimit is returned by DecodeBody when the decoded output exceeds the limit; the returned bytes are the truncated prefix.
var ErrNotFound = errors.New("store: not found")
ErrNotFound is returned by lookups for ids that are not in the store.
var ErrUnsupportedEncoding = errors.New("store: unsupported content encoding")
ErrUnsupportedEncoding is returned for a Content-Encoding token DecodeBody does not know.
var LLMHosts = []string{
"api.anthropic.com", "api.openai.com", "*.openai.azure.com",
"generativelanguage.googleapis.com", "openrouter.ai", "api.groq.com",
"api.mistral.ai", "api.together.xyz", "api.x.ai", "api.deepseek.com",
"bedrock-runtime.*.amazonaws.com",
}
LLMHosts are recognised LLM API endpoints (glob).
Functions ¶
func BodyText ¶
BodyText returns the searchable text of a body: the decoded bytes when the MIME class is textual, they decode and are valid UTF-8, capped at SearchTextCap. Anything else yields false.
func DecodeBody ¶
DecodeBody removes a Content-Encoding from b. Supported tokens: gzip, x-gzip, deflate (zlib-wrapped or raw), br, zstd, identity. Comma-chained encodings ("gzip, br") are undone in reverse order of application. Output is bounded by limit bytes (0 = DefaultDecodeLimit); when exceeded the truncated prefix is returned together with ErrDecodeLimit. Identity and empty encodings return b unchanged.
func FormatDuration ¶
FormatDuration renders compactly: 850µs, 18ms, 3.21s, 1m05s.
func MatchClient ¶
MatchClient compares a filter value with a flow's client address ("ip:port"). "remote" selects every client that is not the machine itself.
func ParseTime ¶
ParseTime parses an absolute (RFC3339) or relative ("15m", "2d") time spec anchored at now. Exported so the TUI can mirror since/until locally.
func Query ¶
Query lists flows from the ring newest-first honouring filter, limit and cursor ("before:<id>"). Returns rows, total matches, and the next cursor. bodies, when non-nil, lets Q search decoded textual bodies too.
func StatusMatcher ¶
StatusMatcher parses "500", "4xx", "400-499", "!2xx", "200|204". Nil means any.
Types ¶
type Matcher ¶
type Matcher struct {
// contains filtered or unexported fields
}
Matcher is a compiled FlowFilter.
func Compile ¶
func Compile(f api.FlowFilter, now time.Time) *Matcher
Compile prepares a filter. now anchors relative times.
func (*Matcher) Match ¶
Match reports whether fl satisfies the filter. Q is a case-insensitive substring match over URL, headers and error, and over decoded textual bodies when WithBodies was set.
func (*Matcher) WithBodies ¶
WithBodies makes Q also search decoded textual bodies fetched through fn. Without it Q matches URL, headers and the error only.
type Mem ¶
type Mem struct {
// OnEvict, if set, is called (without the lock held) for every flow that
// leaves the ring — capacity eviction, Delete and Clear — so dependent
// per-flow state (WebSocket messages) can be released with it.
OnEvict func(*flow.Flow)
// contains filtered or unexported fields
}
Mem is a fixed-size ring of flow snapshots, newest last. Flows are immutable snapshots; Upsert replaces by ID. When the ring is full the oldest flow is evicted to make room.
func (*Mem) Delete ¶
Delete removes every flow for which match returns true and reports how many were removed. Order and IDs of the remaining flows are preserved.
type MemBlobs ¶
type MemBlobs struct {
// contains filtered or unexported fields
}
MemBlobs is an LRU byte-budgeted in-memory blob store. Bodies of the least recently used flows are dropped once the budget is exceeded; a flow whose body was dropped still lists, it just has no body to show.
func NewMemBlobs ¶
NewMemBlobs creates a store with the given byte budget (0 = 256 MiB).
type Sessions ¶
type Sessions struct {
// contains filtered or unexported fields
}
Sessions is the in-memory session registry: named groups of flows, exactly one of which is current. Flows record the id of the session they were captured under; List computes per-session counts with the callback it is given. The registry starts with DefaultSessionName current and is gone with the daemon.
func NewSessions ¶
func NewSessions() *Sessions
NewSessions returns a registry whose current session is DefaultSessionName.
func (*Sessions) Delete ¶
Delete forgets a session. Its flows are the caller's to remove (see Mem.Delete). Deleting the current session is refused with ErrCurrent.
type WSLog ¶
type WSLog struct {
// contains filtered or unexported fields
}
WSLog keeps captured WebSocket messages per flow in memory. Each flow keeps at most perFlow messages (the newest; older ones are dropped and counted) and the whole log stays under a byte budget by forgetting the flows that started logging earliest. Drop releases a flow's messages when it leaves the ring.
func NewWSLog ¶
NewWSLog creates a log keeping at most perFlow messages per flow (0 = 1000) under a total budget of budget bytes of payload (0 = 64 MiB).
func (*WSLog) Dropped ¶
Dropped reports how many messages of a flow were forgotten to stay within the per-flow cap.