store

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

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

View Source
const DefaultDecodeLimit = 8 << 20

DefaultDecodeLimit bounds DecodeBody output when limit is 0.

View Source
const DefaultSessionName = "default"

DefaultSessionName is the name of the session every daemon starts in.

View Source
const SearchTextCap = 256 << 10

SearchTextCap bounds how many decoded body bytes a text search (Q) looks at per body.

Variables

View Source
var ErrCurrent = errors.New("store: cannot delete the current session")

ErrCurrent is returned by Delete for the current session.

View Source
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.

View Source
var ErrNotFound = errors.New("store: not found")

ErrNotFound is returned by lookups for ids that are not in the store.

View Source
var ErrUnsupportedEncoding = errors.New("store: unsupported content encoding")

ErrUnsupportedEncoding is returned for a Content-Encoding token DecodeBody does not know.

View Source
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

func BodyText(ref flow.BodyRef, bodies BodyFunc) (string, bool)

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

func DecodeBody(encoding string, b []byte, limit int64) ([]byte, error)

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 Flags

func Flags(f *flow.Flow) []string

Flags computes the marker list shown in rows.

func FormatBytes

func FormatBytes(n int64) string

FormatBytes renders 0, 812, 8.1k, 22.4k, 1.2M.

func FormatDuration

func FormatDuration(d time.Duration) string

FormatDuration renders compactly: 850µs, 18ms, 3.21s, 1m05s.

func Hash

func Hash(b []byte) string

Hash returns the sha256 hex of b.

func IsLLMHost

func IsLLMHost(host string) bool

IsLLMHost reports whether host is a known LLM API.

func IsTextual

func IsTextual(class string) bool

IsTextual is mimeclass.IsTextual.

func MatchClient

func MatchClient(want, addr string) bool

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

func ParseTime(s string, now time.Time) (time.Time, bool)

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

func Query(m *Mem, filter api.FlowFilter, limit int, now time.Time, bodies BodyFunc) api.FlowList

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 Row

func Row(f *flow.Flow) api.FlowRow

Row renders the one-line list representation.

func StatusMatcher

func StatusMatcher(spec string) func(int) bool

StatusMatcher parses "500", "4xx", "400-499", "!2xx", "200|204". Nil means any.

func TypeClass

func TypeClass(ct string) string

TypeClass is mimeclass.Of.

Types

type Blobs

type Blobs interface {
	Put(b []byte) string
	Get(hash string) ([]byte, bool)
}

Blobs is a content-addressed byte store.

type BodyFunc

type BodyFunc func(flow.BodyRef) ([]byte, bool)

BodyFunc fetches the raw wire bytes of a body by reference.

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

func (m *Matcher) Match(fl *flow.Flow) bool

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

func (m *Matcher) WithBodies(fn BodyFunc) *Matcher

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 NewMem

func NewMem(size int) *Mem

NewMem creates a ring holding at most size flows.

func (*Mem) Cap

func (m *Mem) Cap() int

Cap is the ring size.

func (*Mem) Clear

func (m *Mem) Clear()

Clear empties the ring.

func (*Mem) Count

func (m *Mem) Count(match func(*flow.Flow) bool) int

Count returns how many flows satisfy match.

func (*Mem) Delete

func (m *Mem) Delete(match func(*flow.Flow) bool) int

Delete removes every flow for which match returns true and reports how many were removed. Order and IDs of the remaining flows are preserved.

func (*Mem) Each

func (m *Mem) Each(fn func(*flow.Flow) bool)

Each visits flows newest first until fn returns false.

func (*Mem) Get

func (m *Mem) Get(id flow.ID) (*flow.Flow, bool)

Get returns a flow by ID.

func (*Mem) Len

func (m *Mem) Len() int

Len is the number of flows held.

func (*Mem) Newest

func (m *Mem) Newest() flow.ID

Newest returns the highest ID present.

func (*Mem) Total

func (m *Mem) Total() int64

Total is the number of distinct flows ever inserted.

func (*Mem) Upsert

func (m *Mem) Upsert(f *flow.Flow)

Upsert stores a snapshot.

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

func NewMemBlobs(budget int64) *MemBlobs

NewMemBlobs creates a store with the given byte budget (0 = 256 MiB).

func (*MemBlobs) Bytes

func (m *MemBlobs) Bytes() int64

Bytes is the total size of the blobs held.

func (*MemBlobs) Clear

func (m *MemBlobs) Clear()

Clear drops every blob.

func (*MemBlobs) Get

func (m *MemBlobs) Get(hash string) ([]byte, bool)

Get fetches by hash.

func (*MemBlobs) Len

func (m *MemBlobs) Len() int

Len is the number of blobs held.

func (*MemBlobs) Put

func (m *MemBlobs) Put(b []byte) string

Put stores b and returns its hash.

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) CurrentID

func (s *Sessions) CurrentID() string

CurrentID returns the id of the current session.

func (*Sessions) Delete

func (s *Sessions) Delete(id string) error

Delete forgets a session. Its flows are the caller's to remove (see Mem.Delete). Deleting the current session is refused with ErrCurrent.

func (*Sessions) List

func (s *Sessions) List(flows func(id string) int) []api.Session

List returns every session newest first; flows(id) supplies the count.

func (*Sessions) Start

func (s *Sessions) Start(name string) api.Session

Start ends the current session and makes a new one with a short random id current. An empty name becomes DefaultSessionName.

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

func NewWSLog(perFlow int, budget int64) *WSLog

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) Add

func (w *WSLog) Add(m *flow.WSMessage)

Add records a message.

func (*WSLog) Clear

func (w *WSLog) Clear()

Clear forgets everything.

func (*WSLog) Drop

func (w *WSLog) Drop(id flow.ID)

Drop forgets a flow's messages.

func (*WSLog) Dropped

func (w *WSLog) Dropped(id flow.ID) int

Dropped reports how many messages of a flow were forgotten to stay within the per-flow cap.

func (*WSLog) Messages

func (w *WSLog) Messages(id flow.ID, limit int) []flow.WSMessage

Messages returns up to limit messages of a flow in capture order (0 = all).

func (*WSLog) Stats

func (w *WSLog) Stats() (flows, messages int, bytes int64)

Stats reports the number of flows with messages, the number of messages and their payload bytes.

Jump to

Keyboard shortcuts

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