Parakeet is a Rust-based Bluesky AppServer aiming to implement most of the functionality required to support the Bluesky client
appview atproto bluesky rust appserver
69
fork

Configure Feed

Select the types of activity you want to include in your feed.

postgates: trust provided timestamp only when backfilling

mia.omg.lol 2103b7d9 1e908e61

verified
+44 -15
+1 -1
consumer/src/backfill/repo.rs
··· 144 144 db::maintain_self_labels(t, did, Some(cid), &at_uri, labels).await?; 145 145 } 146 146 if let Some(embed) = rec.embed.clone().and_then(|embed| embed.into_bsky()) { 147 - db::post_embed_insert(t, &at_uri, embed, rec.created_at).await?; 147 + db::post_embed_insert(t, &at_uri, embed, rec.created_at, true).await?; 148 148 } 149 149 150 150 deltas.incr(did, AggregateType::ProfilePost).await;
+42 -13
consumer/src/db/record.rs
··· 5 5 use deadpool_postgres::GenericClient; 6 6 use ipld_core::cid::Cid; 7 7 use lexica::community_lexicon::bookmarks::Bookmark; 8 + use std::collections::HashSet; 8 9 9 10 pub async fn record_upsert<C: GenericClient>( 10 11 conn: &mut C, ··· 317 318 repo: &str, 318 319 cid: Cid, 319 320 rec: AppBskyFeedPost, 321 + is_backfill: bool, 320 322 ) -> PgExecResult { 321 323 let cid = cid.to_string(); 322 324 let record = serde_json::to_value(&rec).unwrap(); ··· 350 352 .await?; 351 353 352 354 if let Some(embed) = rec.embed.and_then(|embed| embed.into_bsky()) { 353 - post_embed_insert(conn, at_uri, embed, rec.created_at).await?; 355 + post_embed_insert(conn, at_uri, embed, rec.created_at, is_backfill).await?; 354 356 } 355 357 356 358 Ok(count) ··· 380 382 post: &str, 381 383 embed: AppBskyEmbed, 382 384 created_at: DateTime<Utc>, 385 + is_backfill: bool, 383 386 ) -> PgExecResult { 384 387 match embed { 385 388 AppBskyEmbed::Images(embed) => post_embed_image_insert(conn, post, embed).await, 386 389 AppBskyEmbed::Video(embed) => post_embed_video_insert(conn, post, embed).await, 387 390 AppBskyEmbed::External(embed) => post_embed_external_insert(conn, post, embed).await, 388 391 AppBskyEmbed::Record(embed) => { 389 - post_embed_record_insert(conn, post, embed, created_at).await 392 + post_embed_record_insert(conn, post, embed, created_at, is_backfill).await 390 393 } 391 394 AppBskyEmbed::RecordWithMedia(embed) => { 392 - post_embed_record_insert(conn, post, embed.record, created_at).await?; 395 + post_embed_record_insert(conn, post, embed.record, created_at, is_backfill).await?; 393 396 match *embed.media { 394 397 AppBskyEmbed::Images(embed) => post_embed_image_insert(conn, post, embed).await, 395 398 AppBskyEmbed::Video(embed) => post_embed_video_insert(conn, post, embed).await, ··· 476 479 ).await 477 480 } 478 481 482 + const PG_DISABLE_RULE: &str = "app.bsky.feed.postgate#disableRule"; 479 483 async fn post_embed_record_insert<C: GenericClient>( 480 484 conn: &mut C, 481 485 post: &str, 482 486 embed: AppBskyEmbedRecord, 483 487 post_created_at: DateTime<Utc>, 488 + is_backfill: bool, 484 489 ) -> PgExecResult { 485 490 // strip "at://" then break into parts by '/' 486 491 let parts = embed.record.uri[5..].split('/').collect::<Vec<_>>(); 487 492 488 493 let detached = if parts[1] == "app.bsky.feed.post" { 489 - let postgate_effective: Option<DateTime<Utc>> = conn 490 - .query_opt( 491 - "SELECT created_at FROM postgates WHERE post_uri=$1", 492 - &[&post], 493 - ) 494 - .await? 495 - .map(|v| v.get(0)); 494 + let pg_data = postgate_get(conn, post).await?; 496 495 497 - postgate_effective 498 - .map(|v| Utc::now().min(post_created_at) > v) 499 - .unwrap_or_default() 496 + if let Some((effective, detached, rules)) = pg_data { 497 + let detached: HashSet<String> = HashSet::from_iter(detached); 498 + let rules: HashSet<String> = HashSet::from_iter(rules); 499 + let compare_date = match is_backfill { 500 + true => post_created_at, 501 + false => Utc::now(), 502 + }; 503 + 504 + if detached.contains(post) { 505 + true 506 + } else if rules.contains(PG_DISABLE_RULE) && compare_date > effective { 507 + true 508 + } else { 509 + false 510 + } 511 + } else { 512 + false 513 + } 500 514 } else { 501 515 false 502 516 }; ··· 505 519 "INSERT INTO post_embed_record (post_uri, record_type, uri, cid, detached) VALUES ($1, $2, $3, $4, $5)", 506 520 &[&post, &parts[1], &embed.record.uri, &embed.record.cid.to_string(), &detached], 507 521 ).await 522 + } 523 + 524 + async fn postgate_get<C: GenericClient>( 525 + conn: &mut C, 526 + post: &str, 527 + ) -> PgOptResult<(DateTime<Utc>, Vec<String>, Vec<String>)> { 528 + let res = conn 529 + .query_opt( 530 + "SELECT created_at, detached, rules FROM postgates WHERE post_uri=$1", 531 + &[&post], 532 + ) 533 + .await? 534 + .map(|v| (v.get(0), v.get(1), v.get(2))); 535 + 536 + Ok(res) 508 537 } 509 538 510 539 pub async fn postgate_upsert<C: GenericClient>(
+1 -1
consumer/src/indexer/mod.rs
··· 625 625 }); 626 626 627 627 let labels = record.labels.clone(); 628 - db::post_insert(conn, at_uri, repo, cid, record).await?; 628 + db::post_insert(conn, at_uri, repo, cid, record, false).await?; 629 629 if let Some(labels) = labels { 630 630 db::maintain_self_labels(conn, repo, Some(cid), at_uri, labels).await?; 631 631 }