proto-blue-api 0.3.3

AT Protocol high-level API: agent, rich text, moderation, generated types
Documentation
// Generated by atproto-codegen. Do not edit.
//! Lexicon: app.bsky.unspecced.getPostThreadV2
#![allow(clippy::pedantic, clippy::nursery, clippy::all)]

use serde::{Deserialize, Serialize};

/// (NOTE: this endpoint is under development and WILL change without notice. Don't use it until it is moved out of `unspecced` or your application WILL break) Get posts in a thread. It is based in an anchor post at any depth of the tree, and returns posts above it (recursively resolving the parent, without further branching to their replies) and below it (recursive replies, with branching to their replies). Does not require auth, but additional metadata and filtering will be applied for authed requests.
/// XRPC Query: app.bsky.unspecced.getPostThreadV2
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Params {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub above: Option<bool>,
    pub anchor: proto_blue_syntax::AtUri,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub below: Option<i64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub branching_factor: Option<i64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub sort: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Output {
    pub has_other_replies: bool,
    pub thread: Vec<ThreadItem>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub threadgate: Option<crate::app::bsky::feed::defs::ThreadgateView>,
}

/// Errors a `call()` on this method can return.
#[derive(Debug, thiserror::Error)]
pub enum CallError {
    #[error("{0}")]
    Xrpc(proto_blue_xrpc::XrpcError),
    #[error(transparent)]
    Transport(#[from] proto_blue_xrpc::Error),
    #[error(transparent)]
    Json(#[from] serde_json::Error),
}

fn map_xrpc_error(err: proto_blue_xrpc::XrpcError) -> CallError {
    CallError::Xrpc(err)
}

fn to_query_params(p: &Params) -> proto_blue_xrpc::QueryParams {
    let mut qp = proto_blue_xrpc::QueryParams::new();
    if let Some(v) = &p.above {
        qp.insert(
            "above".to_string(),
            proto_blue_xrpc::QueryValue::Boolean(*v),
        );
    }
    {
        let v = &p.anchor;
        qp.insert(
            "anchor".to_string(),
            proto_blue_xrpc::QueryValue::String(v.to_string()),
        );
    }
    if let Some(v) = &p.below {
        qp.insert(
            "below".to_string(),
            proto_blue_xrpc::QueryValue::Integer(*v),
        );
    }
    if let Some(v) = &p.branching_factor {
        qp.insert(
            "branchingFactor".to_string(),
            proto_blue_xrpc::QueryValue::Integer(*v),
        );
    }
    if let Some(v) = &p.sort {
        qp.insert(
            "sort".to_string(),
            proto_blue_xrpc::QueryValue::String(v.to_string()),
        );
    }
    qp
}

/// Execute the query.
pub async fn call(
    client: &proto_blue_xrpc::XrpcClient,
    params: Option<&Params>,
    opts: Option<&proto_blue_xrpc::CallOptions>,
) -> Result<Output, CallError> {
    let qp = params.map(to_query_params);
    let response = match client
        .query("app.bsky.unspecced.getPostThreadV2", qp.as_ref(), opts)
        .await
    {
        Ok(r) => r,
        Err(proto_blue_xrpc::Error::Xrpc(x)) => return Err(map_xrpc_error(x)),
        Err(e) => return Err(CallError::Transport(e)),
    };
    Ok(serde_json::from_value(response.data)?)
}

/// Register a typed handler for this method on an [`proto_blue_xrpc::XrpcServer`].
#[cfg(feature = "server")]
pub fn register<F, Fut>(
    server: proto_blue_xrpc::XrpcServer,
    handler: F,
) -> proto_blue_xrpc::XrpcServer
where
    F: Fn(proto_blue_xrpc::HandlerContext, Option<Params>) -> Fut + Send + Sync + 'static,
    Fut: std::future::Future<Output = Result<Output, proto_blue_xrpc::XrpcServerError>>
        + Send
        + 'static,
{
    let handler = std::sync::Arc::new(handler);
    server.query("app.bsky.unspecced.getPostThreadV2", move |ctx| {
        let handler = handler.clone();
        async move {
            let params = params_from_ctx(&ctx);
            let out = handler(ctx, params).await?;
            let value = serde_json::to_value(&out).map_err(|e| {
                proto_blue_xrpc::XrpcServerError::new(
                    proto_blue_xrpc::ResponseType::InternalServerError,
                    format!("output serialize: {e}"),
                )
            })?;
            Ok::<_, proto_blue_xrpc::XrpcServerError>(value)
        }
    })
}

#[cfg(feature = "server")]
fn params_from_ctx(ctx: &proto_blue_xrpc::HandlerContext) -> Option<Params> {
    // Always construct a `Params` — required fields are
    // validated upstream by the lexicon validator when enabled;
    // missing values surface as runtime errors from the handler.
    Some(Params {
        above: ctx.params.get("above").and_then(|v| v.parse::<bool>().ok()),
        anchor: (ctx
            .params
            .get("anchor")
            .and_then(|v| proto_blue_syntax::AtUri::new(v).ok()))?,
        below: ctx.params.get("below").and_then(|v| v.parse::<i64>().ok()),
        branching_factor: ctx
            .params
            .get("branchingFactor")
            .and_then(|v| v.parse::<i64>().ok()),
        sort: ctx.params.get("sort").cloned(),
    })
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "$type")]
pub enum ThreadItemValueRefs {
    #[serde(rename = "app.bsky.unspecced.defs#threadItemPost")]
    BskyUnspeccedDefsThreadItemPost(Box<crate::app::bsky::unspecced::defs::ThreadItemPost>),
    #[serde(rename = "app.bsky.unspecced.defs#threadItemNoUnauthenticated")]
    BskyUnspeccedDefsThreadItemNoUnauthenticated(
        Box<crate::app::bsky::unspecced::defs::ThreadItemNoUnauthenticated>,
    ),
    #[serde(rename = "app.bsky.unspecced.defs#threadItemNotFound")]
    BskyUnspeccedDefsThreadItemNotFound(Box<crate::app::bsky::unspecced::defs::ThreadItemNotFound>),
    #[serde(rename = "app.bsky.unspecced.defs#threadItemBlocked")]
    BskyUnspeccedDefsThreadItemBlocked(Box<crate::app::bsky::unspecced::defs::ThreadItemBlocked>),
    #[serde(other)]
    Other,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ThreadItem {
    pub depth: i64,
    pub uri: proto_blue_syntax::AtUri,
    pub value: ThreadItemValueRefs,
}