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
67
fork

Configure Feed

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

feat(lexica): move StrongRef and Blob into lexica

Mia d19a50fd a3349d80

+77 -76
+1
Cargo.lock
··· 2276 2276 version = "0.1.0" 2277 2277 dependencies = [ 2278 2278 "chrono", 2279 + "cid", 2279 2280 "serde", 2280 2281 "serde_json", 2281 2282 ]
+3 -12
consumer/src/backfill/mod.rs
··· 6 6 use deadpool_postgres::{Object, Pool, Transaction}; 7 7 use did_resolver::Resolver; 8 8 use ipld_core::cid::Cid; 9 + use lexica::StrongRef; 9 10 use metrics::counter; 10 11 use parakeet_db::types::{ActorStatus, ActorSyncState}; 11 12 use redis::aio::MultiplexedConnection; ··· 267 268 268 269 #[derive(Debug, Default)] 269 270 struct CopyStore { 270 - likes: Vec<( 271 - String, 272 - records::StrongRef, 273 - Option<records::StrongRef>, 274 - DateTime<Utc>, 275 - )>, 271 + likes: Vec<(String, StrongRef, Option<StrongRef>, DateTime<Utc>)>, 276 272 posts: Vec<(String, Cid, records::AppBskyFeedPost)>, 277 - reposts: Vec<( 278 - String, 279 - records::StrongRef, 280 - Option<records::StrongRef>, 281 - DateTime<Utc>, 282 - )>, 273 + reposts: Vec<(String, StrongRef, Option<StrongRef>, DateTime<Utc>)>, 283 274 blocks: Vec<(String, String, DateTime<Utc>)>, 284 275 follows: Vec<(String, String, DateTime<Utc>)>, 285 276 list_items: Vec<(String, records::AppBskyGraphListItem)>,
+3 -2
consumer/src/db/copy.rs
··· 7 7 use ipld_core::cid::Cid; 8 8 use tokio_postgres::binary_copy::BinaryCopyInWriter; 9 9 use tokio_postgres::types::Type; 10 + use lexica::StrongRef; 10 11 11 12 // StrongRefs are used in both likes and reposts 12 13 const STRONGREF_TYPES: &[Type] = &[ ··· 20 21 ]; 21 22 type StrongRefRow = ( 22 23 String, 23 - records::StrongRef, 24 - Option<records::StrongRef>, 24 + StrongRef, 25 + Option<StrongRef>, 25 26 DateTime<Utc>, 26 27 ); 27 28
+5 -5
consumer/src/db/record.rs
··· 371 371 let stmt = conn.prepare("INSERT INTO post_embed_images (post_uri, seq, cid, mime_type, alt, width, height) VALUES ($1, $2, $3, $4, $5, $6, $7)").await?; 372 372 373 373 for (idx, image) in embed.images.iter().enumerate() { 374 - let cid = image.image.r#ref.to_string(); 374 + let cid = image.image.cid.to_string(); 375 375 let width = image.aspect_ratio.as_ref().map(|v| v.width); 376 376 let height = image.aspect_ratio.as_ref().map(|v| v.height); 377 377 ··· 398 398 post: &str, 399 399 embed: AppBskyEmbedVideo, 400 400 ) -> PgExecResult { 401 - let cid = embed.video.r#ref.to_string(); 401 + let cid = embed.video.cid.to_string(); 402 402 let width = embed.aspect_ratio.as_ref().map(|v| v.width); 403 403 let height = embed.aspect_ratio.as_ref().map(|v| v.height); 404 404 ··· 411 411 let stmt = conn.prepare_cached("INSERT INTO post_embed_video_captions (post_uri, cid, mime_type, language) VALUES ($1, $2, $3, $4)").await?; 412 412 413 413 for caption in captions { 414 - let cid = caption.file.r#ref.to_string(); 414 + let cid = caption.file.cid.to_string(); 415 415 conn.execute( 416 416 &stmt, 417 417 &[&post, &cid, &caption.file.mime_type, &caption.lang], ··· 429 429 embed: AppBskyEmbedExternal, 430 430 ) -> PgExecResult { 431 431 let thumb_mime = embed.external.thumb.as_ref().map(|v| v.mime_type.clone()); 432 - let thumb_cid = embed.external.thumb.as_ref().map(|v| v.r#ref.to_string()); 432 + let thumb_cid = embed.external.thumb.as_ref().map(|v| v.cid.to_string()); 433 433 434 434 conn.execute( 435 435 "INSERT INTO post_embed_ext (post_uri, uri, title, description, thumb_mime_type, thumb_cid) VALUES ($1, $2, $3, $4, $5, $6)", ··· 634 634 let record = serde_json::to_value(&rec).unwrap(); 635 635 let thumb = rec.embed.as_ref().and_then(|v| v.external.thumb.clone()); 636 636 let thumb_mime = thumb.as_ref().map(|v| v.mime_type.clone()); 637 - let thumb_cid = thumb.as_ref().map(|v| v.r#ref.to_string()); 637 + let thumb_cid = thumb.as_ref().map(|v| v.cid.to_string()); 638 638 639 639 conn.execute( 640 640 include_str!("sql/status_upsert.sql"),
+1 -22
consumer/src/indexer/records.rs
··· 1 1 use crate::utils; 2 2 use chrono::{DateTime, Utc}; 3 - use ipld_core::cid::Cid; 4 3 use lexica::app_bsky::actor::{ChatAllowIncoming, ProfileAllowSubscriptions, Status}; 5 4 use lexica::app_bsky::embed::AspectRatio; 6 5 use lexica::app_bsky::labeler::LabelerPolicy; 7 6 use lexica::app_bsky::richtext::FacetMain; 8 7 use lexica::com_atproto::label::SelfLabels; 9 8 use lexica::com_atproto::moderation::{ReasonType, SubjectType}; 9 + use lexica::{Blob, StrongRef}; 10 10 use serde::{Deserialize, Serialize}; 11 11 use serde_with::serde_as; 12 - 13 - #[derive(Clone, Debug, Deserialize, Serialize)] 14 - pub struct StrongRef { 15 - #[serde( 16 - deserialize_with = "utils::cid_from_string", 17 - serialize_with = "utils::cid_as_str" 18 - )] 19 - pub cid: Cid, 20 - pub uri: String, 21 - } 22 - 23 - #[derive(Clone, Debug, Deserialize, Serialize)] 24 - #[serde(tag = "$type")] 25 - #[serde(rename = "blob")] 26 - #[serde(rename_all = "camelCase")] 27 - pub struct Blob { 28 - pub mime_type: String, 29 - #[serde(serialize_with = "utils::cid_as_link")] 30 - pub r#ref: Cid, 31 - pub size: i32, 32 - } 33 12 34 13 #[derive(Debug, Deserialize, Serialize)] 35 14 #[serde(rename_all = "camelCase")]
+5 -34
consumer/src/utils.rs
··· 1 - use ipld_core::cid::Cid; 2 - use serde::{Deserialize, Deserializer, Serialize, Serializer}; 1 + use serde::{Deserialize, Deserializer}; 2 + use lexica::{Blob, StrongRef}; 3 3 4 4 // see https://deer.social/profile/did:plc:63y3oh7iakdueqhlj6trojbq/post/3ltuv4skhqs2h 5 5 pub fn safe_string<'de, D: Deserializer<'de>>(deserializer: D) -> Result<String, D::Error> { ··· 8 8 Ok(str.replace('\u{0000}', "")) 9 9 } 10 10 11 - pub fn cid_from_string<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Cid, D::Error> { 12 - let str = String::deserialize(deserializer)?; 13 - 14 - Cid::try_from(str).map_err(serde::de::Error::custom) 15 - } 16 - 17 - pub fn cid_as_str<S>(inp: &Cid, serializer: S) -> Result<S::Ok, S::Error> 18 - where 19 - S: Serializer, 20 - { 21 - inp.to_string().serialize(serializer) 22 - } 23 - 24 - #[derive(Debug, Deserialize, Serialize)] 25 - pub struct LinkRef { 26 - #[serde(rename = "$link")] 27 - link: String, 28 - } 29 - 30 - pub fn cid_as_link<S>(inp: &Cid, serializer: S) -> Result<S::Ok, S::Error> 31 - where 32 - S: Serializer, 33 - { 34 - LinkRef { 35 - link: inp.to_string(), 36 - } 37 - .serialize(serializer) 38 - } 39 - 40 - pub fn blob_ref(blob: Option<crate::indexer::records::Blob>) -> Option<String> { 41 - blob.map(|blob| blob.r#ref.to_string()) 11 + pub fn blob_ref(blob: Option<Blob>) -> Option<String> { 12 + blob.map(|blob| blob.cid.to_string()) 42 13 } 43 14 44 15 pub fn strongref_to_parts( 45 - strongref: Option<&crate::indexer::records::StrongRef>, 16 + strongref: Option<&StrongRef>, 46 17 ) -> (Option<String>, Option<String>) { 47 18 strongref 48 19 .map(|sr| (sr.uri.clone(), sr.cid.to_string()))
+1
lexica/Cargo.toml
··· 5 5 6 6 [dependencies] 7 7 chrono = { version = "0.4.39", features = ["serde"] } 8 + cid = { version = "0.11", features = ["serde"] } 8 9 serde = { version = "1.0.216", features = ["derive"] } 9 10 serde_json = "1.0.134"
+27 -1
lexica/src/lib.rs
··· 1 - use serde::Serialize; 1 + use cid::Cid; 2 + use serde::{Deserialize, Serialize}; 3 + 4 + pub use utils::LinkRef; 2 5 3 6 pub mod app_bsky; 4 7 pub mod com_atproto; 8 + mod utils; 5 9 6 10 #[derive(Clone, Debug, Serialize)] 7 11 pub struct JsonBytes { 8 12 #[serde(rename = "$bytes")] 9 13 pub bytes: String, 10 14 } 15 + 16 + #[derive(Clone, Debug, Deserialize, Serialize)] 17 + pub struct StrongRef { 18 + #[serde( 19 + deserialize_with = "utils::cid_from_string", 20 + serialize_with = "utils::cid_as_str" 21 + )] 22 + pub cid: Cid, 23 + pub uri: String, 24 + } 25 + 26 + #[derive(Clone, Debug, Deserialize, Serialize)] 27 + #[serde(tag = "$type")] 28 + #[serde(rename = "blob")] 29 + #[serde(rename_all = "camelCase")] 30 + pub struct Blob { 31 + pub mime_type: String, 32 + #[serde(rename = "ref")] 33 + #[serde(serialize_with = "utils::cid_as_link")] 34 + pub cid: Cid, 35 + pub size: i32, 36 + }
+31
lexica/src/utils.rs
··· 1 + use cid::Cid; 2 + use serde::{Deserialize, Deserializer, Serialize, Serializer}; 3 + 4 + pub fn cid_from_string<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Cid, D::Error> { 5 + let str = String::deserialize(deserializer)?; 6 + 7 + Cid::try_from(str).map_err(serde::de::Error::custom) 8 + } 9 + 10 + pub fn cid_as_str<S>(inp: &Cid, serializer: S) -> Result<S::Ok, S::Error> 11 + where 12 + S: Serializer, 13 + { 14 + inp.to_string().serialize(serializer) 15 + } 16 + 17 + #[derive(Debug, Deserialize, Serialize)] 18 + pub struct LinkRef { 19 + #[serde(rename = "$link")] 20 + link: String, 21 + } 22 + 23 + pub fn cid_as_link<S>(inp: &Cid, serializer: S) -> Result<S::Ok, S::Error> 24 + where 25 + S: Serializer, 26 + { 27 + LinkRef { 28 + link: inp.to_string(), 29 + } 30 + .serialize(serializer) 31 + }