repo

package
v0.2.2 Latest Latest
Warning

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

Go to latest
Published: Jun 19, 2026 License: AGPL-3.0 Imports: 10 Imported by: 0

Documentation

Overview

Package repo is the on-disk tori repository: the path-mapping rules, the record store, the manifest, and the incremental merge. layout.go is the pure heart of it — every file in a repository is a deterministic function of the record it holds, with no network and no clock, so the layout is testable in isolation and a re-capture lands on the exact same paths (spec §6).

Index

Constants

View Source
const (
	ManifestFile = "manifest.json"
	StateFile    = "state.json"
	ProfileFile  = "profile.json"
	IndexFile    = "index.html"
	ReadmeFile   = "README.md"
	AssetsDir    = "_assets"
	CSSFile      = "_assets/tori.css"
)

Well-known files at the repository root.

View Source
const (
	TweetsDir  = "tweets"
	ThreadsDir = "threads"
	HTMLDir    = "html"
	MDDir      = "md"
	MediaDir   = "media"
)

Sub-directories that hold the per-record files.

View Source
const SchemaVersion = 1

SchemaVersion is the on-disk manifest layout version, bumped when the repo shape changes so a future tori can migrate an old archive (spec §6.5).

Variables

This section is empty.

Functions

func AvatarPath

func AvatarPath(handle, srcURL, ext string) string

AvatarPath maps a profile avatar to a stable local file keyed by handle and the size segment X embeds in its URL (e.g. _400x400).

func BannerPath

func BannerPath(handle, ext string) string

BannerPath maps a profile banner to a stable local file keyed by handle.

func MediaPath

func MediaPath(typ, key, srcURL, ext string) string

MediaPath maps a media item to its deterministic local file (spec §6.3). The stem is the media key plus the first 6 hex of a sha256 of the source URL, so two renditions of one key never collide and a photo referenced by a thousand tweets resolves to one file. The extension comes from ext (derived from the URL or the Content-Type by the caller).

func MediaSubdir

func MediaSubdir(typ string) string

MediaSubdir is the directory a media type lives under within media/. X serves animated GIFs as mp4, so they get their own bucket distinct from real video.

func Rel

func Rel(from, to string) string

Rel returns the relative path from the directory holding the page at from to the file at to, both repository-relative with forward slashes (spec §6.4). It is what rewrites a media src or a cross-tweet link inside a rendered page so the archive resolves with the network unplugged. It never escapes the repo root because both inputs are already repo-relative.

func ThreadHTML

func ThreadHTML(root string) string

ThreadHTML is a reconstructed conversation rendered as one inert page.

func ThreadMD

func ThreadMD(root string) string

ThreadMD is a reconstructed conversation rendered as one Markdown document.

func TweetHTML

func TweetHTML(id string) string

TweetHTML is the rendered per-tweet page (kage-shape, inert).

func TweetJSON

func TweetJSON(id string) string

TweetJSON is the canonical record path for a tweet id (spec §6.2). The id is a snowflake string used verbatim, so the path is a pure function of the id and a re-capture overwrites the same file.

func TweetMD

func TweetMD(id string) string

TweetMD is the rendered per-tweet Markdown (yomi-shape).

func TweetRaw

func TweetRaw(id string) string

TweetRaw is the untouched upstream payload beside the canonical record (TP3).

Types

type Asset

type Asset struct {
	Key    string `json:"key"`
	Type   string `json:"type"`
	Path   string `json:"path,omitempty"`   // repo-relative local path, empty if not on disk
	Source string `json:"source,omitempty"` // original URL
	Status string `json:"status"`           // local | unavailable | stream-only | skipped
}

Asset records where one media item went on disk, so the repository is honest about exactly what is and is not localised (spec §8).

type Capture

type Capture struct {
	At    string `json:"at"`
	Added int    `json:"added"`
	Tier  string `json:"tier"`
}

Capture records one archive run: when it happened (the --date stamp), how many records it added, and which tier served them. This is the only place a wall-clock value lives in the manifest (TP5).

type Manifest

type Manifest struct {
	Service     string    `json:"service"`
	Target      TargetRef `json:"target"`
	TiersUsed   []string  `json:"tiers_used"`
	Tweets      int       `json:"tweets"`
	Media       int       `json:"media"`
	Threads     int       `json:"threads"`
	Range       Range     `json:"range"`
	Captures    []Capture `json:"captures"`
	MediaIndex  []Asset   `json:"media_index,omitempty"`
	ToriVersion string    `json:"tori_version"`
	Schema      int       `json:"schema"`
}

Manifest is the repository index — the first file tori info, tori add, and tori render read. Its record-bearing fields are sorted deterministically so a re-capture of the same bytes writes a byte-identical manifest (TP5); the only wall-clock values live in Captures and are passed in at the surface boundary.

func LoadManifest

func LoadManifest(root string) (*Manifest, bool, error)

LoadManifest reads manifest.json from a repository root, returning ok=false when the repo does not yet exist.

func NewManifest

func NewManifest(target TargetRef, version string) *Manifest

NewManifest builds an empty manifest for a target.

func (*Manifest) AddCapture

func (m *Manifest) AddCapture(at string, added int, tier string)

AddCapture appends one capture entry.

func (*Manifest) AddTier

func (m *Manifest) AddTier(tier string)

AddTier records that a tier served part of this capture.

func (*Manifest) Save

func (m *Manifest) Save(root string) error

Save writes the manifest deterministically: tiers and media index sorted, indented JSON, trailing newline.

type Range

type Range struct {
	Oldest time.Time `json:"oldest,omitempty"`
	Newest time.Time `json:"newest,omitempty"`
}

Range is the oldest/newest captured tweet timestamp.

type Store

type Store struct {
	Root string
}

Store is a handle on one repository directory. It writes and reads the canonical records, the raw payloads, and the media files; it owns no network and no policy beyond the layout rules in layout.go.

func Open

func Open(dir string) (*Store, error)

Open returns a Store rooted at dir, creating the directory if needed.

func (*Store) Exists

func (s *Store) Exists(rel string) bool

Exists reports whether a repo-relative file is already on disk.

func (*Store) HasTweet

func (s *Store) HasTweet(id string) bool

HasTweet reports whether a canonical record already exists.

func (*Store) LoadProfile

func (s *Store) LoadProfile() (*x.User, bool, error)

LoadProfile reads profile.json, returning ok=false when absent.

func (*Store) LoadTweet

func (s *Store) LoadTweet(id string) (*x.Tweet, error)

LoadTweet reads one canonical record by id.

func (*Store) LoadTweets

func (s *Store) LoadTweets() ([]*x.Tweet, error)

LoadTweets reads every canonical record under tweets/, sorted by id ascending so callers (render, merge, manifest) get a deterministic order (TP5).

func (*Store) WriteMedia

func (s *Store) WriteMedia(rel string, b []byte) error

WriteMedia writes localised media bytes to a repo-relative path.

func (*Store) WriteProfile

func (s *Store) WriteProfile(u *x.User) error

WriteProfile persists the captured User as profile.json.

func (*Store) WriteText

func (s *Store) WriteText(rel, body string) error

WriteText writes an arbitrary repo-relative text file (a rendered page, the CSS, an index).

func (*Store) WriteTweet

func (s *Store) WriteTweet(t *x.Tweet, raw json.RawMessage) error

WriteTweet persists the canonical record and, when present, the untouched upstream payload beside it (TP3). The canonical JSON is indented and sorted by field for a stable, diff-friendly file.

type TargetRef

type TargetRef struct {
	Kind   string `json:"kind"`
	Ref    string `json:"ref"`
	UserID string `json:"user_id,omitempty"`
	Query  string `json:"query,omitempty"`
}

TargetRef identifies what the repository archives (spec §6.5).

Jump to

Keyboard shortcuts

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