media

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Jun 2, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package media implements deterministic media-file extraction for named protocol fields; see docs/specs/phase-k-media-contract.md.

Scope:

  • Per-trace, per-NAMED-FIELD transform of base64 / data-URL payloads into derived files on disk. No synthesis, no inference of media that isn't already explicitly carried by a documented protocol field.
  • The JSONL line on disk remains the source of truth; extracted files are a redundant cache that exists for fast viewer reads and zip-export bundling.

Non-interference:

  • Extract() runs after writer.appendOne has flushed the JSONL line. Any failure logs a WARN and returns the partial slice so the writer pipeline keeps moving. We never return a non-nil error from Extract.

Skip rules:

  • body_b64 is the unparseable-fallback container, NOT an attachment. Extractor skips it entirely.
  • http(s):// and gs:// / file: URL-only references are not fetched.
  • Empty / whitespace base64 strings are silently skipped.

Package owns four files: media.go (public surface), walk.go (generic JSON walker), protocols.go (per-protocol field tables), decode.go (base64 + data-URL + mime helpers). Tests are walk_test.go and protocols_test.go.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// DataDir is the same `${data_dir}` the writer uses. Extracted files
	// live under ${DataDir}/${YYYY-MM-DD}/${keyhash[:8]}/media/${trace_id}/.
	DataDir string
}

Config is the extractor's runtime configuration. Wired by main from the process-level config object; the extractor itself never reads YAML/env.

type Extractor

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

Extractor is the public type. Construct via New, call Extract per trace. Safe for concurrent use across goroutines (no shared mutable state beyond the underlying filesystem).

func New

func New(cfg Config) *Extractor

New constructs an Extractor. cfg.DataDir must be non-empty for files to be written; with an empty DataDir Extract() still walks the bodies and returns metadata but writes no files (test-friendly).

func (*Extractor) Extract

func (e *Extractor) Extract(t trace.Trace, bucket storage.FileID) []MediaFile

Extract walks t.Req.Body and t.Resp.Body, identifies media-bearing fields per the documented protocols, decodes their base64 payloads, writes the files under the bucket's media subtree (<DataDir>/<Date>/<KeyHash8>/media/ <trace_id>/), and returns the list of MediaFile records.

`bucket` is the JSONL bucket FileID the writer just decided for this trace — passing it (rather than re-deriving from t.TsStart) keeps media files co-located with their owning JSONL even when the trace's request time and the writer's chosen bucket differ across a UTC midnight rotation.

Extract never returns an error. Per-file failures are logged at WARN and the corresponding MediaFile is omitted from the returned slice. The writer pipeline must keep moving regardless.

body_b64 is skipped unconditionally; URL-only image references are skipped (no remote fetch). See package doc for the full skip-list.

type MediaFile

type MediaFile struct {
	// Idx is the 0-based ordinal across BOTH sides of the trace, request
	// media first (document order) then response media.
	Idx int `json:"idx"`

	// Side is "req" or "resp".
	Side string `json:"side"`

	// SourceField is the dotted/bracketed JSON path inside the side body
	// where this media was found. Examples:
	//   "messages[0].content[0].image_url.url"
	//   "contents[1].parts[3].inlineData.data"
	SourceField string `json:"sourceField"`

	// MimeType is the protocol-declared mime if present, else inferred from
	// a data: URL header, else "application/octet-stream".
	MimeType string `json:"mimeType"`

	// Extension is the lower-case extension derived ONLY from MimeType
	// (no leading dot). Never inferred from a filename.
	Extension string `json:"extension"`

	// Size is the decoded byte length of the written file.
	Size int64 `json:"size"`

	// Filename is the path relative to the per-key media dir; full disk
	// path is `${DataDir}/${date}/${keyhash[:8]}/${Filename}`.
	// Format: `media/${trace_id}/${idx}.${ext}`.
	Filename string `json:"filename"`
}

MediaFile mirrors the struct in Phase K § 3 exactly. JSON tags are the shape the SQLite mirror / viewer API expect.

Jump to

Keyboard shortcuts

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