Rewrite streaming processing in a more sane way
And also add support for likes and follows
This commit is contained in:
parent
3a54e04bf4
commit
dd33333649
|
@ -85,6 +85,7 @@ impl CommitProcessor for PostIndexer {
|
|||
// TODO: Delete posts from db
|
||||
// self.database.delete_post(&self.db_connection_pool, &uri).await?;
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use atrium_api::com::atproto::sync::subscribe_repos::{Commit, Message};
|
||||
|
||||
use super::proto::Frame;
|
||||
use anyhow::anyhow;
|
||||
use atrium_api::app::bsky::feed::post::Record;
|
||||
use atrium_api::com::atproto::sync::subscribe_repos::{Commit, Message};
|
||||
|
||||
const COLLECTION_POST: &str = "app.bsky.feed.post";
|
||||
const COLLECTION_LIKE: &str = "app.bsky.feed.like";
|
||||
const COLLECTION_FOLLOW: &str = "app.bsky.graph.follow";
|
||||
|
||||
const ACTION_CREATE: &str = "create";
|
||||
const ACTION_DELETE: &str = "delete";
|
||||
|
||||
#[async_trait]
|
||||
pub trait CommitProcessor {
|
||||
|
@ -27,9 +32,28 @@ pub enum Operation {
|
|||
languages: HashSet<String>,
|
||||
text: String,
|
||||
},
|
||||
CreateLike {
|
||||
author_did: String,
|
||||
cid: String,
|
||||
uri: String,
|
||||
subject_cid: String,
|
||||
subject_uri: String,
|
||||
},
|
||||
CreateFollow {
|
||||
author_did: String,
|
||||
cid: String,
|
||||
uri: String,
|
||||
subject: String,
|
||||
},
|
||||
DeletePost {
|
||||
uri: String,
|
||||
},
|
||||
DeleteLike {
|
||||
uri: String,
|
||||
},
|
||||
DeleteFollow {
|
||||
uri: String,
|
||||
},
|
||||
}
|
||||
|
||||
pub async fn handle_message<P: CommitProcessor>(message: &[u8], processor: &P) -> Result<()> {
|
||||
|
@ -63,35 +87,78 @@ fn parse_commit_from_message(message: &[u8]) -> Result<Option<Commit>> {
|
|||
async fn extract_operations(commit: &Commit) -> Result<Vec<Operation>> {
|
||||
let mut operations = Vec::new();
|
||||
|
||||
let (items, _) = rs_car::car_read_all(&mut commit.blocks.as_slice(), true).await?;
|
||||
let (blocks, _header) = rs_car::car_read_all(&mut commit.blocks.as_slice(), true).await?;
|
||||
let blocks_by_cid: HashMap<_, _> = blocks.into_iter().collect();
|
||||
|
||||
for op in &commit.ops {
|
||||
let collection = op.path.split('/').next().expect("op.path is empty");
|
||||
if (op.action != "create" && op.action != "delete") || collection != "app.bsky.feed.post" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let action = op.action.as_str();
|
||||
let uri = format!("at://{}/{}", commit.repo, op.path);
|
||||
|
||||
if let Some((_, item)) = items.iter().find(|(cid, _)| Some(*cid) == op.cid) {
|
||||
let record: Record = ciborium::from_reader(&mut item.as_slice())?;
|
||||
let operation = match action {
|
||||
ACTION_CREATE => {
|
||||
let cid = match op.cid {
|
||||
Some(cid) => cid,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
operations.push(match op.action.as_str() {
|
||||
"create" => Operation::CreatePost {
|
||||
languages: record.langs.unwrap_or_default().iter().cloned().collect(),
|
||||
text: record.text,
|
||||
author_did: commit.repo.clone(),
|
||||
cid: op
|
||||
.cid
|
||||
.ok_or(anyhow!(
|
||||
"cid is not present for a post create operation, how is that possible"
|
||||
))?
|
||||
.to_string(),
|
||||
uri,
|
||||
},
|
||||
"delete" => Operation::DeletePost { uri },
|
||||
_ => unreachable!(),
|
||||
});
|
||||
}
|
||||
let block = match blocks_by_cid.get(&cid) {
|
||||
Some(block) => block,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
match collection {
|
||||
COLLECTION_POST => {
|
||||
use atrium_api::app::bsky::feed::post::Record;
|
||||
|
||||
let record: Record = ciborium::from_reader(&mut block.as_slice())?;
|
||||
|
||||
Operation::CreatePost {
|
||||
author_did: commit.repo.clone(),
|
||||
cid: cid.to_string(),
|
||||
uri,
|
||||
languages: record.langs.unwrap_or_default().iter().cloned().collect(),
|
||||
text: record.text,
|
||||
}
|
||||
}
|
||||
COLLECTION_LIKE => {
|
||||
use atrium_api::app::bsky::feed::like::Record;
|
||||
|
||||
let record: Record = ciborium::from_reader(&mut block.as_slice())?;
|
||||
|
||||
Operation::CreateLike {
|
||||
author_did: commit.repo.clone(),
|
||||
cid: cid.to_string(),
|
||||
uri,
|
||||
subject_cid: record.subject.cid,
|
||||
subject_uri: record.subject.uri,
|
||||
}
|
||||
}
|
||||
COLLECTION_FOLLOW => {
|
||||
use atrium_api::app::bsky::graph::follow::Record;
|
||||
|
||||
let record: Record = ciborium::from_reader(&mut block.as_slice())?;
|
||||
|
||||
Operation::CreateFollow {
|
||||
author_did: commit.repo.clone(),
|
||||
cid: cid.to_string(),
|
||||
uri,
|
||||
subject: record.subject,
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
ACTION_DELETE => match collection {
|
||||
COLLECTION_POST => Operation::DeletePost { uri },
|
||||
COLLECTION_LIKE => Operation::DeleteLike { uri },
|
||||
COLLECTION_FOLLOW => Operation::DeleteFollow { uri },
|
||||
_ => continue,
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
operations.push(operation)
|
||||
}
|
||||
|
||||
Ok(operations)
|
||||
|
|
Loading…
Reference in New Issue