Files
maarcadetweet/crates/appview/Cargo.toml
T
tomdeboneandClaude Opus 5 124a90dc07 feat(appview): PDS-Firehose konsumieren
Gegenstück zum subscribeRepos-Endpoint: WebSocket-Consumer mit
persistiertem seq-Cursor, Reconnect-Backoff und Behandlung von
#info/OutdatedCursor.

Eigene Cursor-Tabelle statt einer Zeile in jetstream_cursor: dort steht ein
time_us in der Größenordnung 1.7e15, die seq ist ein kleiner Zähler ab 1.
Geteilt hätte GREATEST den PDS-Cursor sofort in eine Zukunft geschoben, die
die PDS nie erreicht.

Kein neuer Indexer-Pfad — jede Op wird in die Single-Op-Form übersetzt, die
apply_commit schon vom Jetstream kennt. Push und Firehose liefern denselben
Commit doppelt; das ist unkritisch, weil die Schreibpfade Upserts sind und
der Dedupe-Index der Notifications den Rest abfängt. Mit einem Test
festgehalten statt vorausgesetzt.

Der CAR-Reader ist neu (es gab nur einen Writer, und der liegt in einem
Binary-Crate ohne lib-Target). Der CBOR-Reader arbeitet mit explizitem
Offset, weil ein Frame zwei hintereinander geschriebene Werte sind, und
akzeptiert CID-Links in beiden Schreibweisen — die Blöcke tragen Strings.

/healthz meldet beide Ströme getrennt; sie fallen unabhängig voneinander
aus.

Verifiziert mit totem Push-Ziel: der Post kam trotzdem an.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013HC9HLrUU1LNwkzp8nkDLX
2026-09-10 07:08:23 +02:00

62 lines
1.9 KiB
TOML

[package]
name = "appview"
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
description = "maarcadetweet AppView (bin)"
[lints.rust]
unsafe_code = "forbid"
[lib]
name = "appview"
path = "src/lib.rs"
[[bin]]
name = "appview"
path = "src/main.rs"
[dependencies]
tokio = { workspace = true }
dotenvy = { workspace = true }
axum = { workspace = true }
tower = { workspace = true }
tower-http = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
anyhow = { workspace = true }
sqlx = { workspace = true }
chrono = { workspace = true }
async-trait = { workspace = true }
at-shared = { workspace = true }
at-firehose = { workspace = true }
at-crypto = { workspace = true }
at-identity = { workspace = true }
reqwest = { workspace = true }
uuid = { workspace = true }
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "logging", "tls12"] }
base64 = { workspace = true }
futures = { workspace = true }
# The local PDS firehose (`src/pds_firehose.rs`): a WebSocket carrying
# DAG-CBOR frames whose `blocks` field is a CAR of record blocks.
# `tokio-tungstenite` for the socket, `cid` for the block addresses,
# `ciborium` for the record blocks themselves (they are written with
# `ciborium::into_writer` on the PDS side, so it is their exact inverse).
# The frame envelope is decoded by `src/cbor.rs`, which needs no crate.
tokio-tungstenite = { workspace = true }
cid = { workspace = true }
ciborium = { workspace = true }
[dev-dependencies]
tokio = { workspace = true }
reqwest = { workspace = true }
serde_json = { workspace = true }
uuid = { workspace = true }
# Unit tests in `src/auth.rs` build a P-256 verification key in the
# same `0x8012 + uncompressed point` encoding the PDS publishes, which
# needs the curve's `ToEncodedPoint`.
p256 = { workspace = true }