Documentation
¶
Overview ¶
Package diagnostics records a bounded, owner-confirmed support capture and builds one redacted ZIP. It does not persist captures, change playback, or accept paths, URLs, or commands from the caller.
Index ¶
- Constants
- Variables
- func Alias(scope, raw string) string
- func LogCorrelated(rec LogRecord, q LogQuery) bool
- type Candidate
- type CaptureView
- type ConnectivityFact
- type Deps
- type DeviceInfo
- type Event
- type FinishIn
- type Gap
- type HardwareFact
- type Hypothesis
- type IdentityPreview
- type Kind
- type LogQuery
- type LogRecord
- type MediaFacts
- type Observation
- type Preview
- type Recorder
- func (r *Recorder) Archive(token, id string) ([]byte, error)
- func (r *Recorder) Devices() []DeviceInfo
- func (r *Recorder) Discard(token, id string) error
- func (r *Recorder) Expire()
- func (r *Recorder) Finish(token, id string, in FinishIn) (CaptureView, error)
- func (r *Recorder) Get(token, id string) (CaptureView, error)
- func (r *Recorder) Observe(e Event)
- func (r *Recorder) SelectDevice(token, id, deviceID string) (CaptureView, error)
- func (r *Recorder) Start(token string, in StartIn) (CaptureView, error)
- type SessionFact
- type Settings
- type StartIn
- type StorageFact
Constants ¶
const Schema = "ether.support.v1"
Schema is the archive manifest version.
Variables ¶
Functions ¶
func Alias ¶
Alias is a stable pseudonym. The same raw id always maps to the same alias, and different ids do not share one.
func LogCorrelated ¶
LogCorrelated reports whether rec belongs to this capture by an exact correlation field inside the capture window. A shorter id is not a match for a longer one, and free text is not searched.
Types ¶
type Candidate ¶
type Candidate struct {
Protocol string
Height int
VideoCodec string
AudioCodec string
Size int64
Score float64
Accepted bool
Rejected bool
Reason string
Name string
}
Candidate is a bounded, URL-free source fact.
type CaptureView ¶
type CaptureView struct {
ID string `json:"id"`
State string `json:"state"`
DeviceConfirmed bool `json:"deviceConfirmed"`
StartedAt time.Time `json:"startedAt"`
Deadline time.Time `json:"deadline"`
FinishedAt *time.Time `json:"finishedAt,omitempty"`
Category string `json:"category"`
Note string `json:"note,omitempty"`
IncludeTitles bool `json:"includeTitles"`
IncludeUsernames bool `json:"includeUsernames"`
IncludeAddresses bool `json:"includeAddresses"`
Device *DeviceInfo `json:"device,omitempty"`
Discovery []DeviceInfo `json:"discovery,omitempty"`
Observations []Observation `json:"observations"`
Hypotheses []Hypothesis `json:"hypotheses"`
Coverage []Gap `json:"coverage"`
Preview *Preview `json:"preview,omitempty"`
}
CaptureView is the owner-console state of one capture.
type ConnectivityFact ¶
type ConnectivityFact struct {
RemoteAccess bool `json:"remoteAccess"`
SecureConnections string `json:"secureConnections,omitempty"`
CertificateConfigured bool `json:"certificateConfigured"`
PublicPort int `json:"publicPort,omitempty"`
}
ConnectivityFact has no public host, custom URL, or certificate path.
type Deps ¶
type Deps struct {
Now func() time.Time
Version string
Commit string
Platform string
Container string // "yes", "no", or "" when the caller could not tell
Secrets func() []string
Settings func() (Settings, error)
// Sessions returns facts for deviceKey and a count of sessions that
// belonged to someone else and were not copied into the slice.
Sessions func(deviceKey string) (matched []SessionFact, omitted int, err error)
Hardware func() (HardwareFact, error)
Storage func() (StorageFact, error)
Connectivity func() (ConnectivityFact, error)
// LogExtract returns structured records. Callers correlate on exact
// fields inside [From, Until] and must not match substrings.
LogExtract func(q LogQuery) (records []LogRecord, truncated bool, err error)
}
Deps are the only inputs the archive collectors may use.
type DeviceInfo ¶
type DeviceInfo struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Model string `json:"model,omitempty"`
Product string `json:"product,omitempty"`
Version string `json:"version,omitempty"`
Platform string `json:"platform,omitempty"`
LastSeen time.Time `json:"lastSeen"`
SuggestedKind string `json:"suggestedKind,omitempty"`
}
DeviceInfo is the owner-console card. ID is an opaque hash, not a client id.
type Event ¶
type Event struct {
Time time.Time
// Until is the last arrival merged into this event. A coalesced span
// is bounded by Time, not by the previous arrival. Zero means Time.
Until time.Time
Kind Kind
Protocol string
DeviceKey string
SessionKey string
AttemptKey string
Method string
Route string
Status int
Duration time.Duration
Bytes int64
Range string
Repeat int
Product string
Platform string
Model string
DeviceName string
AppVersion string
QualityRequested string
QualitySelected string
Profile string
Decision string
Reason string
Rejection string
ErrorExcerpt string
FFmpegExcerpt string
Title string
SourceName string
Username string
Peer string
// Uncorrelated is set when a correlation id was too long to retain.
// The id is not stored, so it cannot be merged with another id.
Candidates []Candidate
Media *MediaFacts
}
Event is one neutral observation. String fields are clipped before the event is stored.
type FinishIn ¶
type FinishIn struct {
IncludeTitles bool `json:"includeTitles"`
IncludeUsernames bool `json:"includeUsernames"`
IncludeAddresses bool `json:"includeAddresses"`
SetFlags bool `json:"-"`
}
FinishIn replaces the inclusion flags used for the ZIP. The finish response previews the exact usernames and addresses that will be inside.
type Gap ¶
type Gap struct {
Collector string `json:"collector"`
Status string `json:"status"`
Detail string `json:"detail"`
}
Gap is something the package does not contain, and why.
type HardwareFact ¶
type HardwareFact struct {
Name string `json:"name,omitempty"`
FFmpeg string `json:"ffmpeg,omitempty"`
Available bool `json:"available"`
}
HardwareFact has no device node paths.
type Hypothesis ¶
Hypothesis is an inference kept separate from observations.
type IdentityPreview ¶
type IdentityPreview struct {
UsernamesIncluded bool `json:"usernamesIncluded"`
AddressesIncluded bool `json:"addressesIncluded"`
Usernames []string `json:"usernames,omitempty"`
Addresses []string `json:"addresses,omitempty"`
Titles []string `json:"titles,omitempty"`
TitlesIncluded bool `json:"titlesIncluded"`
Explanation string `json:"explanation"`
}
IdentityPreview states exactly which usernames and addresses the ZIP will contain. Values are present only when that inclusion flag is on.
type Kind ¶
type Kind string
Kind is one observed fact. ClassifyRequest never returns a source rejection or an encoder result; those are recorded only by an explicit Observe from the component that actually decided.
const ( KindDevice Kind = "device.seen" KindPlaybackRequested Kind = "playback.requested" KindSourceChosen Kind = "source.chosen" KindSourceRejected Kind = "source.rejected" KindStreamRequested Kind = "stream.requested" KindEncoderStarted Kind = "encoder.started" KindEncoderFailed Kind = "encoder.failed" KindMediaRequest Kind = "media.request" KindMediaBytes Kind = "media.bytes" KindTimelineReceived Kind = "timeline.received" KindPlaybackReported Kind = "playback.reported" KindPoll Kind = "client.poll" KindTranscodeDecision Kind = "transcode.decision" )
func ClassifyRequest ¶
ClassifyRequest maps a request to an observation.
A poll, including HTTP 404, is only KindPoll. A playlist request is only KindStreamRequested. KindMediaBytes requires a successful media response, not merely bytes written: a 404 or 500 body is KindMediaRequest. /:/timeline is KindTimelineReceived until the handler records KindPlaybackReported itself. This function never returns KindPlaybackReported, KindSourceRejected, KindSourceChosen, KindEncoderStarted, or KindEncoderFailed.
type LogQuery ¶
type LogQuery struct {
From time.Time
Until time.Time
DeviceKey string
SessionKeys []string
AttemptKeys []string
MaxLines int
}
LogQuery selects log records for one confirmed capture.
type LogRecord ¶
LogRecord is one structured log row. Message is free text and is not exported.
func ParseLogLine ¶
ParseLogLine reads a slog-style line into structured fields. It returns false when the line has no key=value fields.
type MediaFacts ¶
type MediaFacts struct {
Container string `json:"container,omitempty"`
VideoCodec string `json:"videoCodec,omitempty"`
AudioCodec string `json:"audioCodec,omitempty"`
Height int `json:"height,omitempty"`
Width int `json:"width,omitempty"`
BitrateKbps int `json:"bitrateKbps,omitempty"`
Channels string `json:"channels,omitempty"`
}
MediaFacts is probe information safe to export. It has no URLs.
type Observation ¶
type Observation struct {
At time.Time `json:"at"`
Kind Kind `json:"kind"`
Count int `json:"count,omitempty"`
Status int `json:"status,omitempty"`
Route string `json:"route,omitempty"`
Bytes int64 `json:"bytes,omitempty"`
Device string `json:"device,omitempty"`
}
Observation is one fact shown to the owner. It is not a diagnosis.
type Preview ¶
type Preview struct {
Files []string `json:"files"`
Omitted []string `json:"omitted,omitempty"`
Identity IdentityPreview `json:"identity"`
Note string `json:"note,omitempty"`
Redaction string `json:"redaction"`
}
Preview is the inclusion list shown before download. Files is the sealed archive inventory. It is empty until Finish freezes the ZIP, and then it matches that ZIP's members in order.
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
func (*Recorder) Archive ¶
Archive returns the ZIP for the capture that created it. Any other credential gets the same not-found result as an unknown id.
func (*Recorder) Devices ¶
func (r *Recorder) Devices() []DeviceInfo
Devices returns device cards seen within deviceRecent. Ids are opaque.
func (*Recorder) Expire ¶
func (r *Recorder) Expire()
Expire drops finished captures past their retention and finishes recordings past the deadline so a disconnected browser cannot leave one open.
func (*Recorder) Finish ¶
func (r *Recorder) Finish(token, id string, in FinishIn) (CaptureView, error)
Finish closes the capture and builds the ZIP. The returned view lists the exact usernames and addresses that were written, when those flags are on.
func (*Recorder) Observe ¶
Observe retains one bounded event. Ordinary device sightings update the device table and do not take a ring slot.
func (*Recorder) SelectDevice ¶
func (r *Recorder) SelectDevice(token, id, deviceID string) (CaptureView, error)
SelectDevice confirms a discovered or recent device. A stale id leaves the capture unconfirmed.
type SessionFact ¶
type SessionFact struct {
DeviceKey string
State string
Decision string
Quality string
Title string
Username string
Peer string
Bytes int64
}
SessionFact is one playback session before projection. DeviceKey selects correlation and is not exported. Username, title, and peer are omitted from the session file; usernames and addresses are exported only from the identity preview when the owner opts in.
type Settings ¶
type Settings struct {
LogLevel string `json:"logLevel,omitempty"`
FriendlyName string `json:"friendlyName,omitempty"`
QualityDefault string `json:"qualityDefault,omitempty"`
QualityRemote string `json:"qualityRemote,omitempty"`
ProfileName string `json:"profileName,omitempty"`
ProfileMaxHeight int `json:"profileMaxHeight,omitempty"`
ProfileAllowHDR bool `json:"profileAllowHdr,omitempty"`
HWAccel string `json:"hwAccel,omitempty"`
MaxTranscodes int `json:"maxTranscodes,omitempty"`
RemoteMaxBitrateKbps int `json:"remoteMaxBitrateKbps,omitempty"`
SecureConnections string `json:"secureConnections,omitempty"`
RemoteAccess bool `json:"remoteAccess,omitempty"`
CertificateConfigured bool `json:"certificateConfigured,omitempty"`
CacheBudgetBytes int64 `json:"cacheBudgetBytes,omitempty"`
}
Settings is an explicit safe projection. Callers must not put secrets, filesystem paths, or URLs in it.
type StartIn ¶
type StartIn struct {
DeviceID string `json:"deviceId"`
Category string `json:"category"`
Note string `json:"note"`
IncludeTitles bool `json:"includeTitles"`
IncludeUsernames bool `json:"includeUsernames"`
IncludeAddresses bool `json:"includeAddresses"`
}
StartIn opens a capture. DeviceID empty means the device is not known yet. A device id that is not in the recent table is stale and does not open a capture. Notes are kept, truncated, and treated as untrusted data.
type StorageFact ¶
type StorageFact struct {
CacheBudgetBytes int64 `json:"cacheBudgetBytes,omitempty"`
DiskFreeBytes int64 `json:"diskFreeBytes,omitempty"`
DiskFreeKnown bool `json:"diskFreeKnown"`
}
StorageFact has no cache directory.