use crate::atproto::{Client, GetError, PostError, Session};
use crate::lexicon::app::bsky::actor::ProfileViewDetailed;
use crate::lexicon::app::bsky::feed::{AuthorFeed, FeedViewPost, Post};
use crate::lexicon::com::atproto::repo::CreateRecordOutput;
use crate::storage::Storage;
pub struct Bluesky<T: Storage<Session>> {
client: Client<T>,
}
impl<T: Storage<Session>> Bluesky<T> {
pub fn new(client: Client<T>) -> Self {
Self { client }
}
pub async fn actor_get_profile(
&mut self,
actor: &str,
) -> Result<ProfileViewDetailed, GetError<T>> {
self.client
.xrpc_get("app.bsky.actor.getProfile", Some(&[("actor", actor)]))
.await
}
pub async fn feed_post(
&mut self,
repo: &str,
post: Post,
) -> Result<CreateRecordOutput, PostError<T>> {
self.client
.repo_create_record(repo, "app.bsky.feed.post", &post)
.await
}
pub async fn feed_get_author_feed(
&mut self,
author: &str,
mut limit: usize,
) -> Result<Vec<FeedViewPost>, GetError<T>> {
let mut feed = Vec::new();
let mut cursor: Option<String> = None;
while limit > 0 {
let query_limit = std::cmp::min(limit, 100).to_string();
let mut query = Vec::from([("actor", author), ("limit", &query_limit)]);
if let Some(cursor) = cursor.as_ref() {
query.push(("cursor", cursor));
}
let mut subset = self
.client
.xrpc_get::<AuthorFeed>("app.bsky.feed.getAuthorFeed", Some(&query))
.await?;
cursor = subset.cursor.take();
if subset.feed.is_empty() {
break;
}
limit -= subset.feed.len();
feed.append(&mut subset.feed);
}
Ok(feed)
}
}