very fast at protocol indexer with flexible filtering, xrpc queries, cursor-backed event stream, and more, built on fjall
rust fjall at-protocol atproto indexer
58
fork

Configure Feed

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

[api] implement getLatestCommit

dawn 55497e14 a85020df

+62
+1
README.md
··· 314 314 - `com.atproto.sync.listHosts` 315 315 - `com.atproto.sync.getRepoStatus` 316 316 - `com.atproto.sync.listRepos` 317 + - `com.atproto.sync.getLatestCommit` 317 318 318 319 ### systems.gaze.hydrant.* 319 320
+58
src/api/xrpc/get_latest_commit.rs
··· 1 + use jacquard_api::com_atproto::sync::get_latest_commit::{ 2 + GetLatestCommitError, GetLatestCommitOutput, GetLatestCommitRequest, GetLatestCommitResponse, 3 + }; 4 + use jacquard_common::{CowStr, types::cid::Cid}; 5 + 6 + use crate::types::RepoStatus; 7 + 8 + use super::*; 9 + 10 + pub async fn handle( 11 + State(hydrant): State<Hydrant>, 12 + ExtractXrpc(req): ExtractXrpc<GetLatestCommitRequest>, 13 + ) -> XrpcResult<Json<GetLatestCommitOutput<'static>>, GetLatestCommitError<'static>> { 14 + let nsid = GetLatestCommitResponse::NSID; 15 + 16 + let Some(state) = hydrant 17 + .repos 18 + .get(&req.did) 19 + .state() 20 + .await 21 + .map_err(|e| internal_error(nsid, e))? 22 + else { 23 + return Err(XrpcErrorResponse { 24 + status: StatusCode::NOT_FOUND, 25 + error: XrpcError::Xrpc(GetLatestCommitError::RepoNotFound(None)), 26 + }); 27 + }; 28 + 29 + // return specific errors for inactive account states 30 + let xrpc_err = match &state.status { 31 + RepoStatus::Takendown => Some(GetLatestCommitError::RepoTakendown(None)), 32 + RepoStatus::Suspended => Some(GetLatestCommitError::RepoSuspended(None)), 33 + RepoStatus::Deactivated => Some(GetLatestCommitError::RepoDeactivated(None)), 34 + _ => None, 35 + }; 36 + if let Some(err) = xrpc_err { 37 + return Err(XrpcErrorResponse { 38 + status: StatusCode::FORBIDDEN, 39 + error: XrpcError::Xrpc(err), 40 + }); 41 + } 42 + 43 + // return whatever we last recorded; if we haven't synced at all yet, we have nothing to give 44 + let (Some(data), Some(rev_db)) = (state.data, state.rev) else { 45 + return Err(XrpcErrorResponse { 46 + status: StatusCode::NOT_FOUND, 47 + error: XrpcError::Xrpc(GetLatestCommitError::RepoNotFound(Some(CowStr::Borrowed( 48 + "repo still backfilling", 49 + )))), 50 + }); 51 + }; 52 + 53 + Ok(Json(GetLatestCommitOutput { 54 + cid: Cid::from(data), 55 + rev: rev_db.to_tid(), 56 + extra_data: None, 57 + })) 58 + }
+3
src/api/xrpc/mod.rs
··· 10 10 list_records::{ListRecordsOutput, ListRecordsRequest, Record as RepoRecord}, 11 11 }; 12 12 use jacquard_api::com_atproto::sync::get_host_status::GetHostStatusRequest; 13 + use jacquard_api::com_atproto::sync::get_latest_commit::GetLatestCommitRequest; 13 14 use jacquard_api::com_atproto::sync::get_repo_status::GetRepoStatusRequest; 14 15 use jacquard_api::com_atproto::sync::list_hosts::ListHostsRequest; 15 16 use jacquard_api::com_atproto::sync::list_repos::ListReposRequest; ··· 28 29 mod count_records; 29 30 mod describe_repo; 30 31 mod get_host_status; 32 + mod get_latest_commit; 31 33 mod get_record; 32 34 mod get_repo_status; 33 35 mod list_hosts; ··· 42 44 .route(DescribeRepo::PATH, get(describe_repo::handle)) 43 45 .route(GetHostStatusRequest::PATH, get(get_host_status::handle)) 44 46 .route(ListHostsRequest::PATH, get(list_hosts::handle)) 47 + .route(GetLatestCommitRequest::PATH, get(get_latest_commit::handle)) 45 48 .route(GetRepoStatusRequest::PATH, get(get_repo_status::handle)) 46 49 .route(ListReposRequest::PATH, get(list_repos::handle)) 47 50 }