uiattr

package
v0.164.0 Latest Latest
Warning

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

Go to latest
Published: Nov 11, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package uiattr attributes requests of a wire trace to UI actions (P14): clicks, keys, scrolls, typing, shortcuts and menu items of the traced tdesktop build, and synthetic actions of the app.

A first pass (Builder.Add) collects actions, markers, view state and requests; Builder.Finish resolves the attribution of every req.new with this precedence:

  1. sync: the request has a "ui" stamp with rel "sync" (emitted inside the input scope). Exact.
  2. chain: the request has a "cause" with req R: it gets the attribution of R (memoised, depth limited), with Parent R and Root the first request of the chain. cause.req 0 (an update handler) means update-driven. A chain whose root is update-driven or background stays so: ViaChain always leads to an action.
  3. deferred: a "deferred" stamp within Options.DeferredWindow.
  4. after: an "after" stamp (or a deferred one beyond the deferred window) within Options.AfterWindow. Weak. Stamps written inside a nested event loop (a scope open for more than 500 ms, dt counted from the scope open) are "after" stamps whose dt points back at an input record of the action; they are kept beyond the window, as Nested.
  5. none: background traffic (timers, pings, config, getDifference after reconnect).

Requests without a stamp and without a cause are background, unless Options.Infer is set: then main-thread requests are attributed by time to the latest action (deferred or after windows, from the last event of that action), marked Inferred.

Traces without UI events resolve every request to update or none.

Index

Constants

View Source
const (
	ServerMaxMsgID    = int64(1) << 56
	ScheduledMaxMsgID = ServerMaxMsgID + int64(1)<<32
	ShortcutMaxMsgID  = ScheduledMaxMsgID + int64(1)<<32

	StartClientMsgID  = 1 - int64(1)<<58
	EndClientMsgID    = StartClientMsgID + int64(1)<<31
	StartStoryMsgID   = EndClientMsgID + 1
	EndStoryMsgID     = StartStoryMsgID + int64(1)<<30
	SpecialMsgIDShift = EndStoryMsgID
)

Message id ranges of tdesktop (Telegram/SourceFiles/data/data_msg_id.h). Server message ids are in (0, ServerMaxMsgID); the client uses the other ranges for local, story, scheduled and shortcut messages and for special "show at" values.

View Source
const (
	DefaultDeferredWindow = 150 * time.Millisecond
	DefaultAfterWindow    = 3 * time.Second
	DefaultMaxChain       = 16
)

Defaults of Options.

View Source
const (
	ActionPress    = "press"
	ActionClick    = "click"
	ActionKey      = "key"
	ActionScroll   = "scroll"
	ActionType     = "type"
	ActionShortcut = "shortcut"
	ActionMenu     = "menu"
	// ActionApp is a synthetic action: a semantic event with no input
	// parent ("src":"app").
	ActionApp = "app"
	// ActionUnknown is an action referenced by stamps whose input record is
	// missing (e.g. in a deleted segment).
	ActionUnknown = "unknown"
)

Action kinds.

View Source
const NestedMS = 500

NestedMS is the age of an input scope after which the emitter stamps events inside it as "after" (a nested event loop).

Variables

Vias lists attribution kinds in precedence order.

Functions

func IsUIKind

func IsUIKind(kind string) bool

IsUIKind reports whether kind is a UI record (ui.* or app.*).

func MsgIDLabel

func MsgIDLabel(id int64) string

MsgIDLabel formats a tdesktop message id: server ids as numbers, special values by name (ShowAtUnreadMsgId is "unread", ShowAtTheEndMsgId "end", ServerMaxMsgId-1, the "newest message" anchor, "newest"), and ids of the client ranges as local(N), story(N), scheduled(N) or shortcut(N).

func SemanticLabel

func SemanticLabel(ev *wiretrace.Event, peers map[string]string) string

SemanticLabel describes a semantic or view event, with hashed peers resolved through peers (may be nil): "chat h:5c1e… (user)", "media.open document h:0b77…".

func SemanticToken

func SemanticToken(ev *wiretrace.Event) string

SemanticToken is the alignment token of a semantic or view event: "chat(user)", "media.open(document)", "section(Info::WrapWidget/Settings)", "box(PeerListBox)".

Types

type Action

type Action struct {
	A    uint32
	Kind string
	// Src is "app" for synthetic actions.
	Src string
	// T is the time of the first record of the action; End is the time of
	// its last record (including stamped events).
	T, End float64
	Seq    uint64
	W      int64
	Path   []string
	// Handler is the click handler type, if any.
	Handler string
	// Events are the input records of the action (ui.press, ui.click,
	// ui.scroll, ui.scroll.end, …).
	Events []*wiretrace.Event
	// Semantic are the semantic and view events the action caused
	// (ui.chat, ui.media.open, …), in order.
	Semantic []*wiretrace.Event
	// Requests are the requests attributed to the action, in order.
	Requests []*Request
}

Action is one user (or synthetic app) action.

func (*Action) Label

func (a *Action) Label() string

Label is a short human-readable description of the action itself, e.g. "click Dialogs::InnerWidget", "scroll up HistoryWidget ×14 1.2s".

func (*Action) Token

func (a *Action) Token() string

Token is the alignment token of the action: the kind with its stable arguments plus the semantic events it caused, e.g. "click(Dialogs::InnerWidget)>chat(user)", "scroll(up,HistoryWidget)". Hashed ids, counts and times are left out, so tokens match across runs.

func (*Action) Widget

func (a *Action) Widget() string

Widget is the widget an action is about: for scrolls the owner of the Ui::ScrollArea, otherwise the first path element that is not a generic Ui:: widget (or the receiver).

type Attribution

type Attribution struct {
	// Action is nil for update-driven and background requests.
	Action *Action
	Via    Via
	// Parent is the direct cause request of a chained request; Root is the
	// first request of the chain.
	Parent, Root int64
	// DT is the stamp (or inferred) delay after the action, in ms.
	DT float64
	// Inferred is set for attributions by time (Options.Infer).
	Inferred bool
	// Nested is set for "after" stamps written inside a nested event loop
	// of the action's input scope.
	Nested bool
}

Attribution is the resolved UI attribution of a request.

func (Attribution) UserDriven

func (a Attribution) UserDriven() bool

UserDriven reports whether the request is attributed to an action.

type Builder

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

Builder collects events of one trace.

func NewBuilder

func NewBuilder(opt Options) *Builder

NewBuilder creates a Builder.

func (*Builder) Add

func (b *Builder) Add(ev *wiretrace.Event)

Add adds one event. Events must be added in trace order.

func (*Builder) Finish

func (b *Builder) Finish() *Result

Finish resolves attributions. The Builder must not be used after it.

type ChatView

type ChatView struct {
	Peer     string
	PeerKind string
	Topic    int64
	Msg      int64
	Sublist  bool
}

ChatView is the open chat of a window.

type Marker

type Marker struct {
	N         int64
	T         float64
	Seq       uint64
	Src       string
	Label     string
	LabelUser bool
}

Marker is a "ui.marker" record.

func (*Marker) Token

func (m *Marker) Token() string

Token is the alignment token of a marker: marker(<label>), or marker(#n) without a label.

type Options

type Options struct {
	// DeferredWindow bounds "deferred" stamps (default 150 ms, the emitter
	// kDeferredMs).
	DeferredWindow time.Duration
	// AfterWindow bounds "after" stamps (default 3 s, --ui-window).
	AfterWindow time.Duration
	// MaxChain limits cause chains (default 16).
	MaxChain int
	// Infer attributes unstamped main-thread requests without a cause by
	// time.
	Infer bool
}

Options configures attribution.

type Peer

type Peer struct {
	// Kind is wiretrace.PeerUser, PeerChat or PeerChannel.
	Kind string
	ID   int64
}

Peer is a peer found in a decoded body.

func PeersFrom

func PeersFrom(v any) []Peer

PeersFrom collects the peers of a decoded TL value (tljson objects).

func (Peer) String

func (p Peer) String() string

String returns "user#123".

type Request

type Request struct {
	Req    int64
	Seq    uint64
	T      float64
	Thread string
	Type   uint32
	Size   int64
	Cause  *wiretrace.Cause
	Stamp  *wiretrace.UIStamp
	Caller string

	Done, Failed, Canceled bool
	DoneT                  float64
	LatMS                  float64
	RespLen                int64
	Error                  string

	// View is the view state when the request was created.
	View View
	Attr Attribution
	// contains filtered or unexported fields
}

Request is one req.new with its lifecycle.

func (*Request) Bytes

func (r *Request) Bytes() int64

Bytes is the request size plus the response length.

type Result

type Result struct {
	// Actions are sorted by time.
	Actions []*Action
	ByID    map[uint32]*Action
	Markers []*Marker
	// Requests are in req.new order.
	Requests []*Request
	ByReq    map[int64]*Request
	// Views are view-state events without an action (app.state, ui.box
	// from Show, …), in order.
	Views []*wiretrace.Event
	// HasUI is set when the trace has any UI record (hdr.ui, ui.*, app.*).
	HasUI bool
	// Peers maps hashed peer ids to "user#123" style names, see JoinPeers.
	Peers map[string]string
}

Result is the output of Builder.Finish.

func Build

func Build(run *wiretrace.Run, opt Options) (*Result, error)

Build reads all events of run.

func (*Result) Background

func (r *Result) Background() []*Request

Background returns the requests not attributed to an action.

func (*Result) Describe

func (r *Result) Describe(a *Action) string

Describe is the action label followed by its semantic events: "click Dialogs::InnerWidget → chat h:5c1e… (user)".

func (*Result) JoinPeers

func (r *Result) JoinPeers(key wiretrace.IDKey, peers []Peer)

JoinPeers maps the hashed ids of the trace (Result.Peers) to peers, using the run key (ui.key).

func (*Result) JoinRawPeers

func (r *Result) JoinRawPeers(peers []Peer)

JoinRawPeers maps raw ids (traces written with ui_raw_ids: the decimal PeerId.value) to peers.

type Via

type Via string

Via is how a request was attributed.

const (
	ViaSync     Via = "sync"
	ViaChain    Via = "chain"
	ViaDeferred Via = "deferred"
	ViaAfter    Via = "after"
	ViaUpdate   Via = "update"
	ViaNone     Via = "none"
)

Attribution kinds, in precedence order.

type View

type View struct {
	W       int64
	Chat    *ChatView
	Section string
	// Box is the top shown box type; Layer is set while the window shows a
	// layer (ui.box with "layer":true, the type is not known).
	Box   string
	Layer bool
	// Media is the kind of the open media viewer item (photo, document,
	// story, …); MediaID its (hashed) id.
	Media   string
	MediaID string
	Window  string
	// Session is false after ui.session {"open":false}.
	Session bool
	// Call is the kind of the active call (call, group), if any.
	Call    string
	Account int64

	Locked, Idle, Inactive, ScreenLocked, Sleep bool
	// contains filtered or unexported fields
}

View is the view state at some point of a trace: what the user was looking at in the current main window (the window of the latest UI record with "w").

func (View) Label

func (v View) Label() string

Label is a coarse label of the view: "locked", "media:document", "box:PeerListBox", "box:layer", "chat:user", "section:Info::WrapWidget/Settings" or "none".

Jump to

Keyboard shortcuts

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